zoukankan      html  css  js  c++  java
  • 整体二分

    参考资料:

    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;
    }
    

      

  • 相关阅读:
    往下滚动,导航栏隐藏
    判断是模拟器还是真机
    根据颜色生成图片
    UITextfiled 设置输入前面空格
    iOS 滑动TableView控制导航栏隐藏与显示
    时间 多少分钟前
    时间戳转时间
    iOS 常用公共方法(一)
    找工作感悟
    java 内存泄露
  • 原文地址:https://www.cnblogs.com/Undeadtoad/p/7249340.html
Copyright © 2011-2022 走看看