参考资料:
http://www.cnblogs.com/zig-zag/archive/2013/04/18/3027707.html
http://blog.csdn.net/hbhcy98/article/details/50642773
伪代码:
Divide_Conquer(Q, AL, AR) //Q是当前处理的操作序列 //WANT是要求的贡献,CURRENT为已经累计的贡献(记录的是1~AL-1内所有修改的贡献) //[AL, AR]是询问的答案范围区间 if AL = AR then 将Q中所有是询问操作的答案设为AL end if //我们二分答案,AM为当前的判定答案 AM = (AL+AR) / 2 //Solve是主处理函数,只考虑参数满足判定标准[AL, AM]的修改的贡献,因为CURRENT域中已经记录了[1,AL-1]的修改的贡献了,这一步是保证时间复杂度的关键,因为SOLVE只于当前Q的长度有关,而不与整个操作序列的长度有线性关系,这保证了主定理解出来只多一个log Solve(Q, AL, AM) //Solve之后Q中各个参数满足判定标准的修改对询问的贡献被存储在ANS数组 //Q1,Q2为了两个临时数组,用于划分操作序列 for i = 1 to Length(Q) do if (Q[i].WANT <= Q[i].CURRENT + ANS[i]) then //当前已有贡献不小于要求贡献,说明最终答案应当不大于判定答案 向数组Q1末尾添加Q[i] else //当前已有贡献小于要求贡献,说明最终答案应当大于判定答案 //这里是整体二分的关键,把当前贡献累计入总贡献,以后不再重复统计! Q[i].CURRENT = Q[i].CURRENT + ANS[i] 向数组Q2末尾添加Q[i] end if end for //分治,递归处理 Divide_Conquer(Q1, AL, AM) Divide_Conquer(Q2, AM+1, AR)
代码:
#include<bits/stdc++.h> using namespace std; #define MAXN 1000005 #define inf 1000000000 struct T{ int x,y,z,s,tag,cur; }a[MAXN],a1[MAXN],a2[MAXN]; int cnt=0,tree[MAXN]={},ans[MAXN],tmp[MAXN]; int n,m,q[MAXN]; inline int lowbit(int x){ return x&(-x); } void add(int pos,int x){ for(int i=pos;i<=n;i+=lowbit(i)) tree[i]+=x; } int query(int pos){ int ret=0; for(int i=pos;i>0;i-=lowbit(i)) ret+=tree[i]; return ret; } void divide(int head,int tail,int l,int r){ if(head>tail) return; if(l==r){ for(int i=head;i<=tail;i++) if(a[i].tag==3) ans[a[i].s]=l; return; } int mid=(l+r)>>1; for(int i=head;i<=tail;i++){ if(a[i].tag==1&&a[i].y<=mid) add(a[i].x,1); else if(a[i].tag==2&&a[i].y<=mid) add(a[i].x,-1); else tmp[i]=query(a[i].y)-query(a[i].x-1); } for(int i=head;i<=tail;i++){ if(a[i].tag==1&&a[i].y<=mid) add(a[i].x,-1); if(a[i].tag==2&&a[i].y<=mid) add(a[i].x,1); } int l1=0,l2=0; for(int i=head;i<=tail;i++){ if(a[i].tag==3){ if(a[i].cur+tmp[i]>a[i].z-1) a1[++l1]=a[i]; else{ a[i].cur+=tmp[i]; a2[++l2]=a[i]; } } else{ if(a[i].y<=mid) a1[++l1]=a[i]; else a2[++l2]=a[i]; } } for(int i=1;i<=l1;i++) a[head+i-1]=a1[i]; for(int i=1;i<=l2;i++) a[head+l1+i-1]=a2[i]; divide(head,head+l1-1,l,mid); divide(head+l1,tail,mid+1,r); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&q[i]); a[++cnt].x=i,a[cnt].y=q[i],a[cnt].tag=1,a[cnt].s=0; } char sign; int x,y,z,num=0; for (int i=1;i<=m;i++){ scanf(" %c",&sign); if (sign=='Q'){ scanf("%d%d%d",&x,&y,&z); a[++cnt].x=x,a[cnt].y=y,a[cnt].z=z,a[cnt].tag=3,a[cnt].s=++num; } else{ scanf("%d%d",&x,&y); a[++cnt].x=x,a[cnt].y=q[x],a[cnt].tag=2,a[cnt].s=0; a[++cnt].x=x,a[cnt].y=y,a[cnt].tag=1,a[cnt].s=0; a[x].x=y; } } divide(1,cnt,0,inf); for (int i=1;i<=num;i++) printf("%d ",ans[i]); return 0; }