首页 > 代码库 > Bzoj2683 简单题 [CDQ分治]

Bzoj2683 简单题 [CDQ分治]

Time Limit: 50 Sec  Memory Limit: 128 MB
Submit: 1071  Solved: 428

Description

你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:

 

命令

参数限制

内容

1 x y A

1<=x,y<=N,A是正整数

将格子x,y里的数字加上A

2 x1 y1 x2 y2

1<=x1<= x2<=N

1<=y1<= y2<=N

输出x1 y1 x2 y2这个矩形内的数字和

3

终止程序

Input

输入文件第一行一个正整数N。
接下来每行一个操作。
 

Output

对于每个2操作,输出一个对应的答案。
 

Sample Input

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

1<=N<=500000,操作数不超过200000个,内存限制20M。

对于100%的数据,操作1中的A不超过2000。

Source

 

CDQ分治

第4遍回顾之前抄的代码的时候,突然顿悟。

个人理解,这种分治方法类似于做矩形面积并时候用到的扫描线法。将每个区间修改操作拆成插入/删除,和每个询问操作一起按横坐标x升序排序。

用一个一维数组记录“当前横坐标”对应的y轴情况,从左往右扫描所有操作,并用差分的方式完成修改(在时间维度上差分),记录答案。

↑该一维数组可以用树状数组优化,扫描操作可以用分治方法优化(每层分治时处理前半部分操作对后半部分查询的影响)。

  ↑组合起来就成了CDQ分治。

________

PS1: 这时我想起,两三个个月前RLQ说他研究出一种用树状数组乱搞二维大数据的做法,当时没怎么听懂,也没太在意……卧槽,原来是CDQ分治?

    CDQ分治要是晚出现两年,就变成RLQ分治了……%%%%%

PS2:   之前抄的LCT也已经回顾了10+遍了,是不是也快要顿悟了呢……

________

 

 1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 const int mxn=200010; 9 int read(){10     int x=0,f=1;char ch=getchar();11     while(ch<0 || ch>9){if(ch==-)f=-1;ch=getchar();}12     while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();}13     return x*f;14 }15 int n;16 struct opt{17     int flag;18     int x,y,w;19     int t;20     int id;21 }a[mxn*10],b[mxn*10];22 int cnt=0;23 int cmp(opt q,opt e){24     if(q.x==e.x){25         if(q.y==e.y)return q.flag<e.flag;26         return q.y<e.y;27     }28     return q.x<e.x;29 }30 int ans[mxn];31 int t[mxn*5];32 void add(int x,int v){while(x<=n){t[x]+=v;x+=x&-x;}return;}33 int sum(int x){34     int res=0;35     while(x){res+=t[x];x-=x&-x;}36     return res;37 }38 void solve(int l,int r){39     if(l>=r)return;40     int i,j,mid=(l+r)>>1;41     int l1=l,l2=mid+1;42     for(i=l;i<=r;i++){43         if(a[i].flag==1 && a[i].t<=mid) add(a[i].y,a[i].w);44         else if(a[i].flag==2 && a[i].t>mid) ans[a[i].id]+=sum(a[i].y)*a[i].w;45     }46     for(i=l;i<=r;i++)47         if(a[i].flag==1 && a[i].t<=mid) add(a[i].y,-a[i].w);48     for(i=l;i<=r;i++)49         if(a[i].t<=mid)b[l1++]=a[i];50         else b[l2++]=a[i];51     for(i=l;i<=r;i++)a[i]=b[i];52     solve(l,mid);solve(mid+1,r);53     return;54 }55 int main(){56     n=read();57     int i,j,x,y,c,v;58     int id=0;59     while(1){60         c=read();61         if(c==3)break;62         if(c==1){//修改 63             x=read();y=read();v=read();64             a[++cnt].flag=1;a[cnt].x=x;a[cnt].y=y;a[cnt].w=v;65             a[cnt].t=cnt;66         }67         else{//查询 68             x=read();y=read();c=read();v=read();69             a[++cnt].flag=2;a[cnt].x=x-1;a[cnt].y=y-1;70                 a[cnt].w=1;a[cnt].t=cnt;a[cnt].id=++id;71             a[++cnt].flag=2;a[cnt].x=x-1;a[cnt].y=v;72                 a[cnt].w=-1;a[cnt].t=cnt;a[cnt].id=id;73             a[++cnt].flag=2;a[cnt].x=c;a[cnt].y=y-1;74                 a[cnt].w=-1;a[cnt].t=cnt;a[cnt].id=id;75             a[++cnt].flag=2;a[cnt].x=c;a[cnt].y=v;76                 a[cnt].w=1;a[cnt].t=cnt;a[cnt].id=id;77         }78     }79     sort(a+1,a+cnt+1,cmp);80     solve(1,cnt);81     for(i=1;i<=id;i++){82         printf("%d\n",ans[i]);83     }84     return 0;85 }

 

Bzoj2683 简单题 [CDQ分治]