整体二分

参考资料:

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("\n%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\n",ans[i]);
	return 0;
}

  

posted on 2017-07-28 11:33  Undeadtoad  阅读(111)  评论(1编辑  收藏  举报

导航