zoukankan      html  css  js  c++  java
  • Mokia CDQ分治+容斥

    Mokia CDQ分治+容斥

    题目描述

    维护一个(W imes W)的矩阵,初始值均为(S).每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数(M leq 160000),询问数(Q leq 10000,W leq 2000000).

    输入格式

    第一行两个整数(S,W);其中(S)为矩阵初始值;(W)为矩阵大小
    接下来每行为一下三种输入之一(不包含引号):
    ("1 x y a")
    ("2 x1 y1 x2 y2")
    ("3")
    输入(1):你需要把((x,y))(第(x)行第(y)列)的格子权值增加(a)
    输入(2):你需要求出以左下角为((x1,y1)),右上角为((x2,y2))的矩阵内所有格子的权值和,并输出
    输入(3):表示输入结束

    输出格式

    对于每个输入(2),输出一行,即输入(2)的答案

    样例

    样例输入

    0 4
    1 2 3 3
    2 1 1 3 3
    1 2 2 2
    2 2 2 3 4
    3

    样例输出

    3
    5

    数据范围与提示

    保证答案不会超过(int)范围

    分析

    我们会发现格子很大,但是修改数和查询数比较小

    因此,我们肯定不能维护整个格子,而要从修改和查询上找突破口

    我们设第(i)次修改的点的横纵坐标分别为 (nx,ny) ,如果它要对之后的某个矩形产生贡献的话

    必须满足 (x_1 leq nx leq x_2,y_1leq ny leq y_2)

    如果加上时间的限制,那么就是一个五维的偏序,不好处理

    我们可以用容斥的方法把一个大矩形分成四个小矩形,类似于求前缀和的方法

    (sum[x_2][y_2]-sum[x_2][y_1-1]-sum[x_1-1][y2]+sum[x_1-1][y_1-1])

    (sum[i][j]) 表示原点和 ((i,j)) 围成的矩形所增加的值

    这样问题就变成了一个三维偏序 (i<j,x[i] leq x[j],y[i] leq y[j])

    然后就可以离线用 (CDQ) 分治解决

    代码

    #include<cstdio>
    #include<algorithm>
    inline int read(){
    	int x=0,fh=1;
    	char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=2e6+5;
    struct asd{
    	int id,x,y,wz,val;
    	bool jud;
    	asd(){}
    	asd(int aa,int bb,int cc,int dd,int ee,bool ff){
    		id=aa,x=bb,y=cc,wz=dd,val=ee,jud=ff;
    	}
    }b[maxn];
    int s,w,cnt,js;
    bool cmp1(asd aa,asd bb){
    	if(aa.id==bb.id && aa.x==bb.x) return aa.y<bb.y;
    	if(aa.id==bb.id) return aa.x<bb.x;
    	return aa.id<bb.id;
    }
    bool cmp2(asd aa,asd bb){
    	if(aa.x==bb.x) return aa.y<bb.y;
    	return aa.x<bb.x;
    }
    int lb(int xx){
    	return xx&-xx;
    }
    int tr[maxn];
    void ad(int wz,int val){
    	for(int i=wz;i<maxn;i+=lb(i)){
    		tr[i]+=val;
    	}
    }
    int cx(int wz){
    	int nans=0;
    	for(int i=wz;i>0;i-=lb(i)){
    		nans+=tr[i];
    	}
    	return nans;
    }
    int ans[maxn][6];
    void solve(int l,int r){
    	if(l==r) return;
    	int mids=(l+r)>>1;
    	solve(l,mids);
    	solve(mids+1,r);
    	std::sort(b+l,b+mids+1,cmp2);
    	std::sort(b+mids+1,b+r+1,cmp2);
    	int now=l;
    	for(int i=mids+1;i<=r;i++){
    		while(now<=mids && b[now].x<=b[i].x){
    			if(!b[now].jud){
    				ad(b[now].y,b[now].val);
    			}
    			now++;
    		}
    		if(b[i].jud){
    			ans[b[i].id][b[i].wz]+=cx(b[i].y);
    		}
    	}
    	for(int i=now-1;i>=l;i--){
    		if(!b[i].jud){
    			ad(b[i].y,-b[i].val);
    		}
    	}
    }
    int jl[maxn],anss[maxn];
    int main(){
    	s=read(),w=read();
    	while(1){
    		int aa,bb,cc,dd,ee;
    		aa=read();
    		js++;
    		jl[js]=aa;
    		if(aa==1){
    			bb=read(),cc=read(),dd=read();
    			bb++,cc++;
    			b[++cnt]=asd(js,bb,cc,0,dd,0);
    		} else if(aa==2){
    			bb=read(),cc=read(),dd=read(),ee=read();
    			bb++,cc++,dd++,ee++;
    			b[++cnt]=asd(js,dd,ee,1,0,1);
    			b[++cnt]=asd(js,dd,cc-1,2,0,1);
    			b[++cnt]=asd(js,bb-1,ee,3,0,1);
    			b[++cnt]=asd(js,bb-1,cc-1,4,0,1);
    			anss[js]=(dd-bb+1)*(ee-cc+1)*s;
    		} else {
    			break;
    		}
    	}
    	std::sort(b+1,b+1+cnt,cmp1);
    	solve(1,cnt);
    	for(int i=1;i<js;i++){
    		if(jl[i]==2){
    			printf("%d
    ",ans[i][1]-ans[i][2]-ans[i][3]+ans[i][4]+anss[i]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    C++ string char[] 转化
    c++ 转化
    2014/4/16
    2014/4/11
    垂直电商现倒闭潮
    经典K线组合图解 > 正文
    上下影线
    分​析​主​力​试​盘​手​法
    nginx重新编译不停服
    nexus
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13637466.html
Copyright © 2011-2022 走看看