cdq分治

来源:互联网 发布:光纤销售数据 编辑:程序博客网 时间:2024/04/30 12:23
/*cdq分治模板 程序为例题题解 例题:  来源:G:\苏畅\其他\c++\程序保存\石门中学创新班\2017.8 暑假夏令营\2017.8.8\讲课 分治杂谈.ppt你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作共M次:1、将格子(x,y)里的数字加上d。操作:A x y d 2、输出(x1,y1)为左上角,(x2,y2)为右下角的矩形内数字和。操作:Q x1 y1 x2 y2 N,M<=500000题解:将每次询问分解成2个,对1到x1-1区间y1到y2的询问和对1到x2区间y1到y2的询问。 对时间分治,考虑前面的操作对后面询问的贡献。 然后变成操作全部在前面,询问全部在后面 对修改和询问按照x排序,再次利用时间消去x这个限制,开树状数组以y为下标存贮修改值,遇见操作则加,遇见询问则取y1到y2之和,因为已经按照x排序了,所以前面加入的修改必然对询问产生贡献最后递归求解 注意:见整体二分注意事项 */#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int maxn = 500000 + 100;struct op{int x,y1,y2,d,t,i;//如果是修改,x为横坐标,y为纵坐标,d为修改值 ,t表示时间 bool ask;// 如果是查询,x是横坐标,y1是纵坐标1,y2是纵坐标2 ,d是当前答案,t表示时间 i表示第i个问题 }q[maxn*2],q1[maxn*2],q2[maxn*2]; struct tree{int a[maxn];void add(int x,int d){for(;x<maxn;x+=x&-x) a[x]+=d;}int qsum(int x){int p=0;for(;x>=1;x-=x&-x) p+=a[x];return p;}int sum(int l,int r){return qsum(r)-qsum(l-1);}}t;int n,m,qn,tot;int p[maxn];void read(){int i,x1,x2,y1,y2,d;char c;cin>>n>>m;qn=tot=0;for(i=0;i<m;i++){cin>>c;if(c=='A'){cin>>x1>>y1>>d;q[tot++]= (op){x1,y1,0,d,i,0,false};}else{cin>>x1>>y1>>x2>>y2;if(x1!=1) q[tot++]= (op){x1-1,y1,y2,0,i,qn,true};q[tot++]= (op){x2,y1,y2,0,i,qn,true};qn++;}}}void solve(int ql,int qr,int l,int r)//lr表示当前时间的左右区间,qlqr表示操作序列 {//cout<<l<<' '<<r<<endl;int i,mid,k1,k2;if(ql>qr) return;if(l==r){for(i=ql;i<=qr;i++){if(q[i].ask){int cnt=t.sum(q[i].y1,q[i].y2);q[i].d+=cnt; }else t.add(q[i].y1,q[i].d);}for(i=ql;i<=qr;i++) if(!q[i].ask) t.add(q[i].y1,-q[i].d);return;}mid=(l+r)>>1;k1=k2=0;for(i=ql;i<=qr;i++){if(q[i].ask){if(q[i].t<=mid) q1[k1++]=q[i];else{int cnt=t.sum(q[i].y1,q[i].y2);q[i].d+=cnt; q2[k2++]=q[i]; }}else{if(q[i].t<=mid) t.add(q[i].y1,q[i].d),q1[k1++]=q[i];else            q2[k2++]=q[i];}}for(i=0;i<k1;i++) if(!q1[i].ask) t.add(q1[i].y1,-q1[i].d);for(i=ql;i<ql+k1;i++) q[i]=q1[i-ql];for(i=ql+k1;i<=qr;i++) q[i]=q2[i-ql-k1];solve(ql,ql+k1-1,l,mid);solve(ql+k1,qr,mid+1,r);}bool cmpx(op aa,op bb){return aa.x==bb.x?aa.t<bb.t:aa.x<bb.x;}bool cmpt(op aa,op bb){return aa.t==bb.t?aa.x<bb.x:aa.t<bb.t;}void print(){int i,j;for(i=0;i<tot;i++) if(q[i].ask){if(p[q[i].i]){p[q[i].i]=-p[q[i].i];p[q[i].i]+=q[i].d;}else p[q[i].i]+=q[i].d;}for(i=0;i<qn;i++) cout<<p[i]<<endl;}int main(){freopen("1.in","r",stdin);freopen("1.out","w",stdout);read();sort(q,q+tot,cmpx);//一开始先按照x排序,这样就可以消除x这个限制 solve(0,tot-1,0,m-1);sort(q,q+tot,cmpt);print();return 0;}

原创粉丝点击