1. 程式人生 > >[JZOJ4438] K小數查詢(經典分塊)

[JZOJ4438] K小數查詢(經典分塊)

Description

給你N個數組成的序列,需要支援兩種操作

  • 1 L R xLR加上x
  • 2 L R kLRk小的數

Solution

分塊大法好!

我們將序列分成N塊,每塊中維護原來的順序的值,以及將該塊所有值排序後的值,並且每個值還帶有一個指標指向對應的那個值

修改整塊的就直接打標記,兩邊的暴力重構該塊

關鍵在查詢!

我們可以二分一個答案(思考一下,二分出來的答案會不會序列中不存在呢?)

然後轉化成判定性問題,判斷二分出來的答案是不是在第k

只需要對於每個塊,找該塊中小於這個值的個數,全部加起來看是不是k1,然後逼近答案。

證明一下這樣為什麼不會出現不存在的答案

假設正確答案是s,那麼二分出大於s的答案顯然不可能,因為個數一定要加上s本身這一個

小於等於s,都有可能等於k1,然而二分出來的答案是這些值中的最大值(自己想為什麼)

所以二分出來的一定是s

Code

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--) #define mo 1000000007 using namespace std; int pl[500],wz[80605],n,m,size; struct note { int x,y; }a[80605],b[80605]; bool cmp(note x,note y) { return x.x<y.x; } int nt(int k) { return ((k-1)/size+1)*size+1; } int pd(int l,int r,int k) { int p=nt(l),sum=0,i; note k1; k1.x=k; while
(nt(p)<r+1) { k1.x-=pl[wz[p]]; sum+=lower_bound(b+p,b+nt(p),k1,cmp)-b-p; k1.x+=pl[wz[p]]; p=nt(p); } if (nt(l)>r) { fo(i,l,r) if (a[i].x<k-pl[wz[i]]) sum++; } else { fo(i,l,nt(l)-1) if (a[i].x<k-pl[wz[i]]) sum++; fo(i,p,r) if (a[i].x<k-pl[wz[i]]) sum++; } return sum; } int main() { int i,j; cin>>n; size=(int)sqrt(n); fo(i,1,n) { scanf("%d",&a[i].x); b[i].x=a[i].x; b[i].y=i; } j=1; wz[j]=1; while (j+size<=n+1) { sort(b+j,b+j+size,cmp); j+=size; wz[j]=wz[j-size]+1; } if(j!=n+1) sort(b+j,b+n+1,cmp); fo(i,1,n) { if (wz[i]==0) wz[i]=wz[i-1]; a[b[i].y].y=i; } cin>>m; int i1=0; fo(i,1,m) { int p,l,r,k,j; scanf("%d%d%d%d",&p,&l,&r,&k); if (p==1) { j=nt(l); while (nt(j)<=r) { pl[wz[j]]+=k; j=nt(j); } int q; if (nt(l)>r) { fo(q,l,r) a[q].x=b[a[q].y].x=a[q].x+k; sort(b+nt(l)-size,b+nt(l),cmp); fo(q,nt(l)-size,nt(l)-1) a[b[q].y].y=q; } else { fo(q,l,nt(l)-1) a[q].x=b[a[q].y].x=a[q].x+k; sort(b+nt(l)-size,b+nt(l),cmp); fo(q,nt(l)-size,nt(l)-1) a[b[q].y].y=q; fo(q,j,r) a[q].x=b[a[q].y].x=a[q].x+k; sort(b+j,b+nt(j),cmp); fo(q,j,nt(j)-1) a[b[q].y].y=q; } } else { int x=-5000000,y=5000000,mid; while (x<y-1) { mid=(x+y)/2; if (pd(l,r,mid)<=k-1) x=mid; else y=mid; } if (pd(l,r,y)==k-1) printf("%d\n",y); else printf("%d\n",x); } } }

相關推薦

[JZOJ4438] K小數查詢經典

Description 給你N個數組成的序列,需要支援兩種操作 1 L R x 將L到R加上x 2 L R k 求L到R第k小的數 Solution 分塊大法好! 我們將序列分成N−−√塊,每塊中維護原來的順序的值,以及將該塊所有值

bzoj5037 線段樹練習4加強版暴力

log del string 技術分享 iostream || getc code click   求大爺教線段樹怎麽寫啊QAQ   只會寫分塊...一開始腦抽寫成了O(NKlogN)還被CZL大爺嘲諷了一發T T   f[i][j]表示在第i塊中,模k為j的數有幾個,

【bzoj4765】普通計算姬雙重

efi ref space include pos gif signed problem 。。   題目傳送門:http://www.lydsy.com/JudgeOnline/problem.php?id=4765   這道題已經攢了半年多了。。。因為懶,一直沒去寫。。

bzoj3436: 小K的農場約束

col bsp pac als OS namespace mat else center 3436: 小K的農場 題目:傳送門 題解:   查分基礎:    t==1 a>=b+c    t==2 b>=a-c   t==3 a>=b+

51Nod 1225 - 餘數之和整除

【題目描述】 【思路】 整除分塊+等差數列 設 p = ⌊

【洛谷3396】雜湊衝突大力

點此看題面 大致題意:給你一個長度為nn的陣列valval以及mm個操作,操作有兩種:一種是將valxvalx修改為yy,另一種操作是求出∑vali(i∑vali(i%x=y)x=y)。 樸素的暴力 我們先

牛客網練習賽25A—因數個數和整除

題目描述 q次詢問,每次給一個x,問1到x的因數個數的和。 輸入描述: 第一行一個正整數q ; 接下來q行,每行一個正整數 x 輸出描述: 共q行,每行一個正整數表示答案 題意: 給你一個n,求1的因子數+2的因子數+3的因子數+......+n的因子數。

jzoj5936 【NOIP2018模擬10.29】逛公園 性質+

Description 策策同學特別喜歡逛公園,公園可以看做有n個景點的序列,每個景點會給策策帶來di 的愉悅度,策策初始有x0 的愉悅度,然而愉悅度也是有上限的,他在每個景點的愉悅度上限為li ,策策想要從 l 到 r這一段景點中選擇一段景點參觀(從這一段的左

【洛谷5113】Sabbat of the witch毒瘤

點此看題面 大致題意: 給你一個序列,要你支援三種操作:區間賦值,區間求和,撤回之前任一區間賦值操作。 分塊 這道題應該是一道十分毒瘤的分塊題。 這道題要用到的演算法並不是很難,但是思維難度是真的高。 大致思路就是對於每一個塊維護一大堆資訊,各用一個棧儲存對每個塊的賦值操作,並開一個鄰接表來儲存

查詢區間內等於x的數的個數

問題:有一個有n個數的陣列,q次查詢,每次查詢l, r ,x,查詢區間[l,r]內等於x的數的個數思路:分塊。就把這題當成是分塊的入門題來講解一下分塊。分塊其實就是一種比較優美的暴力(我覺得),一般的分塊都是把長度為n的陣列分成每一塊為sqrt(n)個數的多個塊。然後對於區間

【bzoj2724】蒲公英

sort 大小 int gin algorithm read oid n) 快速合並 題目分析 付費題哈哈。題意就是求區間眾數,由於區間眾數無法快速合並,所以不能使用傳統的數據結構如線段樹等。 這時分塊就能派上很大的用場。將序列分成$\sqrt{n}+$塊,每塊大小$\

HDU 6053 TrickGCD

%d space 復雜 cstring 前綴 == str 結果 logs 【題目鏈接】 http://acm.hdu.edu.cn/showproblem.php?pid=6053 【題目大意】   給出一個數列每個位置可以取到的最大值,   問這個

計蒜客16492 building二分線段樹/

sin cst include sqrt ++ building scanf mat math 題解: 考慮用線段樹維護樓的最大值,然後這個問題就很簡單了。 每次可以向左二分出比x高的第一個樓a,同理也可以向右二分出另一個樓b,如果a,b都存在,答案就是b-a-1。 註意到

Topcoder SRM 675 Div1 500Pts LimitedMemorySeries1

tor bits fin get pre n) ted 多少 top 題意 給定一個長度不超過$5*10^{6}$的數列和不超過$100$個詢問,每次詢問這個數列第$k$小的數,返回所有詢問的和    內存限制很小,小到不能存下這個數列。(數列以種子的形式給出)   

bzoj3920: Yuuna的禮物莫隊+

max ons del closed 感覺 做到 bzoj ace clu   思路挺簡單的,但是總感覺好難寫...碼力還是差勁,最後寫出來也挺醜的   這題顯然是個莫隊題,考慮怎麽轉移和詢問...   根據莫隊修改多查詢少的特點,一般用修改快查詢慢的分塊來維護。查第$

sql 查詢 每次6行

分享 數據 mage com http 行數 -- where SQ -- 對比 數據 是否 相同 select * from [dbo].[ProjecrInfo] where Project_state=‘已審核‘ -- 查詢 已經 審核 有多少數據 -- 每次 按

bzoj3994: [SDOI2015]約數個數和莫比烏斯反演+

put name 一行 AI algorithm scan space 代碼 print www.cnblogs.com/shaokele/ bzoj3994: [SDOI2015]約數個數和   Time Limit: 20 Sec   Memory Limit: 1

BZOJ2821 作詩

span -o 一模一樣 sin include pre getch pan ostream 和區間眾數幾乎一模一樣的套路。 // luogu-judger-enable-o2 #include<iostream> #include<cstdio>

【OJ2130】K小數查詢

很好 print char line 分塊 con 多少 第一個 () 2130 -- K小數查詢(Solution) 題目大意 : 給你一個長度為 \(N\) 的數列和 \(Q\) 個操作,操作包括:①區間加一個數;②詢問區間內第 \(k\) 小的數。\((n,q\le8

BZOJ 3110 [Zjoi2013]K大數查詢整體二分

題解 gre void 有關 pre \n str k大數查詢 如果 3110: [Zjoi2013]K大數查詢 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 11654 Solved: 3505[Submit][Sta