• BZOJ1176: [Balkan2007]Mokia(CDQ+树状数组)


    题意:N*N的矩形 N<=2e6 操作一 单点更新 操作二 查询矩形区域和 我们用三元组(t,x,y)表示第x操作作用(x,y)坐标 然后对于询问拆成四个答案维护即可 跑CDQ把每部分的答案综合起来即可!

    #include <bits/stdc++.h>
    #define ll long long
    const int NM=2e6+10;
    const int nm=2e5+10;
    using namespace std;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f*x;
    }
    typedef struct node{
    	int x,y;int pos,vul;
    }node;
    node d[nm];ll ans[nm];
    node q[nm];
    int n,cnt;
    int p[NM];
    int get_id(int x){return x&(-x);}
    void update(int x,int vul){
    	if(!x||!vul)return ;
    	for(int i=x;i<=n;i+=get_id(i))p[i]+=vul;
    }
    int Sum(int x){
    	int sum=0;
    	for(int i=x;i>0;i-=get_id(i))sum+=p[i];
    	return sum;
    }
    void clear(int x){
    	if(!x)return ;
    	for(int i=x;i<=n;i+=get_id(i))p[i]=0;
    }
    void gui(int l,int mid,int r){
    //	cout<<l<<" "<<mid<<" "<<r<<endl;
    	int i=l;int j=mid+1;int num=0;
    	while(i<=mid&&j<=r){
    		while(i<=mid&&d[i].x<=d[j].x)q[++num]=d[i],update(d[i].y,d[i].vul),i++;
    		q[++num]=d[j];
    	//	cout<<num<<"---==="<<d[j].y<<endl;
    //		update(d[j].y,d[j].vul);
    		if(d[j].pos<0){ans[d[j].pos*-1]-=Sum(d[j].y);}
    		else if(d[j].pos>0){ans[d[j].pos]+=Sum(d[j].y);}
    		j++;
    	//	cout<<num<<endl;
    	}
    	if(i<=mid)while(i<=mid)q[++num]=d[i],update(d[i].y,d[i].vul),i++;
    	if(j<=r){
    		while(j<=r){
    		q[++num]=d[j];
    //		update(d[j].y,d[j].vul);
    		if(d[j].pos<0){ans[d[j].pos*-1]-=Sum(d[j].y);}
    		else if(d[j].pos>0){ans[d[j].pos]+=Sum(d[j].y);}
    		j++;		
    	}
    }
    	for(int k=1;k<=num;k++)d[l+k-1]=q[k],clear(q[k].y);
    }
    void cdq(int l,int r){
    	if(l>=r)return ;
    //	cout<<l<<" "<<r<<endl;
    	int mid=(l+r)>>1;
    	cdq(l,mid);
    	cdq(mid+1,r);
    	gui(l,mid,r);
    	//cout<<l<<"--==="<<r<<endl;
    	//for(int i=l;i<=r;i++)cout<<d[i].x<<" "<<d[i].y<<endl;
    //	cout<<l<<" "<<r<<endl;
    }
    int main(){
    	int s;s=read();n=read();
    	int op;int x,y,x1,y1;
    	while(op=read()){
    		if(op==3)break;
    		if(op==1)d[++cnt].x=read(),d[cnt].y=read(),d[cnt].vul=read(),d[cnt].pos=0,ans[cnt]=-1;
    		else{
    			x=read();y=read();x1=read();y1=read();
    			d[++cnt].x=x-1;d[cnt].y=y-1;d[cnt].pos=cnt;ans[cnt]=1ll*x*y*s;
    			int t1=cnt;
    			d[++cnt].x=x-1;d[cnt].y=y1;d[cnt].pos=-1*t1;ans[t1]-=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1;
    			d[++cnt].x=x1;d[cnt].y=y-1;d[cnt].pos=-1*t1;ans[t1]-=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1;
    			d[++cnt].x=x1;d[cnt].y=y1;d[cnt].pos=t1;ans[t1]+=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1;
    			//cout<<ans[t1]<<endl;
    		}
    	}
    	//cout<<cnt<<endl;
    	cdq(1,cnt);
    	for(int i=1;i<=cnt;i++)if(ans[i]>=0)printf("%lld
    ",ans[i]);
    }
    

      

    1176: [Balkan2007]Mokia

    Time Limit: 30 Sec  Memory Limit: 162 MB
    Submit: 3265  Solved: 1460
    [Submit][Status][Discuss]

    Description

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

    Input

    第一行两个整数,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:表示输入结束

    Output

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

    Sample Input

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

    Sample Output

    3
    5

    HINT

    保证答案不会超过int范围

  • 相关阅读:
    常见网络设备工作原理
    Linux逻辑卷的创建
    关于华为模拟器eNSP-防火墙USG6000V怎么重装镜像
    一人之下(名言吧)
    Struts2学习笔记——Struts2搭建和第一个小程序
    eclipse部署Tomcat9
    通过反射访问类的私有方法(无参)
    Java学习笔记之——IO
    Java学习笔记之——线程的生命周期、线程同步
    Java学习笔记之——多线程
  • 原文地址:https://www.cnblogs.com/wang9897/p/9222325.html
Copyright © 2020-2023  润新知