POJ1195/BZOJ1176 题解,CDQ分治

来源:互联网 发布:数据库运维主要做什么 编辑:程序博客网 时间:2024/06/05 15:59

POJ1195 MOBILE/ BZOJ 1176

这两个题题意完全相同,放在一起说吧

题意:

你有一个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

终止程序

标准的三维偏序问题,三个维度分别为x,y和时间t。

在POJ1195中,N<=1024,可以用二维树状数组来做,非常简单。

但在BZOJ1176中,N<=500000,空间开不下,所以用CDQ分治+一维树状数组来做。

对于所有的查询操作,我们拆分成4个。分别查询(0,0)到(x1-1,y1-1),(x2,y2),(x2,y1-1),(x1-1,y2)四个矩形的数字和

然后用容斥原理加减一下就可以算出(x1,y1),(x2,y2)的矩形数字和了。

CDQ分治中,首先按x来排序,对t这个维度进行分治。

那么t<=mid的更新操作都能影响到t'>=mid+1的查询结果。

所以在CDQ(l,r)中,按照x从小到大扫一遍所有操作,遇到更新操作就在树状数组上插入y值,

遇到查询操作就给该操作的结果加上树状数组上查询到的sum(1,y)的值。

接下来用类似归并排序的方法,把t<=mid的操作都放到数组左半部分,t>=mid+1的操作都放到右半部分

这么做之后两半部分的x依然是有序的,就可以递归处理两半部分之间的更新操作对查询操作产生的影响了。

下面是代码,按照POJ1195的输入格式写的

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<string>#define ll long longusing namespace std;int n;int tree[1029];int cnt=0;int anscnt=0;int ans[60111]; struct operation{int x,y;int k;int id,ansid; bool type;//0,add;1,query operation(int x_,int y_,int k_,bool type_,int id_):x(x_),y(y_),k(k_),type(type_),id(id_){}operation(int x_,int y_,int k_,int ansid_,bool type_,int id_):x(x_),y(y_),k(k_),ansid(ansid_),type(type_),id(id_){}operation(){}bool operator <(const operation& rhs)const{if(x==rhs.x&&y==rhs.y)return type<rhs.type;if(x==rhs.x)return y<rhs.y;return x<rhs.x;}}op[241111],temp[241111];void add(int x,int k){for(x;x<=n;x+=x&-x)tree[x]+=k;}int query(int x){int res=0;for(x;x>0;x-=x&-x)res+=tree[x];return res;}void cdq(int l,int r){//cout<<l<<" "<<r<<endl;if(l==r)return;int mid=l+r>>1,lp=l,rp=mid+1;for(int i=l;i<=r;++i){if(op[i].id<=mid&&!op[i].type)add(op[i].y,op[i].k);if(op[i].id>mid&&op[i].type)ans[op[i].ansid]+=query(op[i].y)*op[i].k;}for(int i=l;i<=r;++i)if(op[i].id<=mid&&!op[i].type)add(op[i].y,-op[i].k);for(int i=l;i<=r;++i)if(op[i].id<=mid)temp[lp++]=op[i];else temp[rp++]=op[i];for(int i=l;i<=r;++i)op[i]=temp[i];cdq(l,mid);cdq(mid+1,r);}int main(){int o;while(scanf("%d",&o),o!=3){int x,y,k,x2,y2;if(o==0)scanf("%d",&n);if(o==1){scanf("%d%d%d",&x,&y,&k);++cnt;op[cnt]=operation(x+1,y+1,k,0,cnt);}else if(o==2){scanf("%d%d%d%d",&x,&y,&x2,&y2);anscnt++;++cnt;op[cnt]=operation(x2+1,y2+1,1,anscnt,1,cnt);++cnt;op[cnt]=operation(x,y2+1,-1,anscnt,1,cnt);++cnt;op[cnt]=operation(x2+1,y,-1,anscnt,1,cnt);++cnt;op[cnt]=operation(x,y,1,anscnt,1,cnt);}}sort(op+1,op+cnt+1);cdq(1,cnt);for(int i=1;i<=anscnt;++i)printf("%d\n",ans[i]);return 0;}



0 0
原创粉丝点击