1. 程式人生 > >HDU - 5412 CRB and Queries (整體二分)

HDU - 5412 CRB and Queries (整體二分)

ems 二分 答案 獨立 查詢 problem pan nbsp 區間

題目鏈接

動態區間第k小,但是這道題的話用主席樹+樹狀數組套線段樹的空間復雜度是O(nlog2n)會爆掉。

另一種替代的方法是用樹狀數組套平衡樹,空間復雜度降到了O(nlogn),但我感覺平衡樹是個挺惡心的東西,而且時間復雜度是O(nlog3n),比主席樹還多了個logn。

最高效的方法是用一個叫整體二分的東西算法,它的基本思想是這樣的:

假設當前所有查詢的答案範圍都在[l,r]之間,設mid=(l+r)/2,那麽我們只處理所有修改後的值在[l,mid]中的修改操作,把不需要執行的修改操作全部扔到後半區間,那麽對於每個詢問操作都可以知道它的答案是在[l,mid]之間還是(mid+1,r]之間,這樣就把所有的詢問劃分到了兩個獨立的區間,然後遞歸處理即可。本質上是將原序列轉化成01序列,這樣處理起來就方便多了。與CDQ分治較為類似,是個很神奇的算法。

空間復雜度O(n),時間復雜度O(nlog2n)

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 const int inf=0x3f3f3f3f;
 5 const int N=1e5+10;
 6 struct QR {
 7     int f,l,r,k,u,x,dx;
 8 } qr[N<<2];
 9 
10 int a[N],c[N],b[N<<2],lq[N<<2],rq[N<<2],nq,tot,ans[N],n,m;
11 int
lowbit(int x) {return x&-x;} 12 void add(int u,int x) { 13 for(; u<=n; u+=lowbit(u))c[u]+=x; 14 } 15 int query(int u) { 16 int ret=0; 17 for(; u; u-=lowbit(u))ret+=c[u]; 18 return ret; 19 } 20 21 void solve(int l,int r,int L,int R) { 22 if(L>R)return; 23 if
(l==r) { 24 for(int i=L; i<=R; ++i)if(qr[b[i]].f)ans[qr[b[i]].u]=l; 25 return; 26 } 27 int nl=0,nr=0,mid=(l+r)>>1; 28 for(int i=L; i<=R; ++i) { 29 if(!qr[b[i]].f) { 30 if(qr[b[i]].x<=mid)add(qr[b[i]].u,qr[b[i]].dx),lq[nl++]=b[i]; 31 else rq[nr++]=b[i]; 32 } else { 33 int t=query(qr[b[i]].r)-query(qr[b[i]].l-1); 34 if(qr[b[i]].k<=t)lq[nl++]=b[i]; 35 else qr[b[i]].k-=t,rq[nr++]=b[i]; 36 } 37 } 38 for(int i=0; i<nl; ++i)if(!qr[lq[i]].f)add(qr[lq[i]].u,-qr[lq[i]].dx); 39 for(int i=0; i<nl; ++i)b[L+i]=lq[i]; 40 for(int i=0; i<nr; ++i)b[L+nl+i]=rq[i]; 41 solve(l,mid,L,L+nl-1); 42 solve(mid+1,r,L+nl,R); 43 } 44 45 int main() { 46 while(scanf("%d",&n)==1) { 47 nq=tot=0; 48 memset(c,0,sizeof c); 49 int maxn=0; 50 for(int i=1; i<=n; ++i) { 51 scanf("%d",&a[i]); 52 maxn=max(maxn,a[i]); 53 qr[nq++]=(QR) {0,0,0,0,i,a[i],1}; 54 } 55 scanf("%d",&m); 56 while(m--) { 57 int f; 58 scanf("%d",&f); 59 if(f==1) { 60 int u,x; 61 scanf("%d%d",&u,&x); 62 qr[nq++]=(QR) {0,0,0,0,u,a[u],-1}; 63 qr[nq++]=(QR) {0,0,0,0,u,a[u]=x,1}; 64 maxn=max(maxn,a[u]); 65 } else { 66 int l,r,k; 67 scanf("%d%d%d",&l,&r,&k); 68 qr[nq++]=(QR) {1,l,r,k,tot++,0,0}; 69 } 70 } 71 for(int i=0; i<nq; ++i)b[i]=i; 72 solve(0,maxn,0,nq-1); 73 for(int i=0; i<tot; ++i)printf("%d\n",ans[i]); 74 } 75 return 0; 76 }

HDU - 5412 CRB and Queries (整體二分)