[BZOJ 1176:单点修改,查询子矩阵和]:
1176: [Balkan2007]Mokia
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 2005 Solved: 894
[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
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
5
HINT
保证答案不会超过int范围
Source
分析:
第一道CDQ分治的题目TAT...
查询的限制——序
对于一个数据结构题而言(或者需要运用数据结构的地方),我们无非就是做两件操作,一是修改,二是查询
对于修改而言,有插入,删除,变更(其实等价于删除再插入)这几种方式
那么查询的本质是什么呢
我们思考所遇到过的数据结构题,可以发现查询实际上就在做一件事情:
把符合本次查询的限制的修改对答案产生的效果合并起来
满足这种限制通常表现为一种序的要求,并且这种序是广义的,符合限制的操作往往是按某种序(或多种序)排序后的操作的前缀
通常来说,查询一定有时间上的限制,也就是要求考虑发生在某个时刻之前的所有查询,对于一个问题而言,假如所有查询要求的发生时刻相同,那这就是一个静态查询问题,如果要求发生的时刻随着查询而变,那这就是一个动态修改问题,动态修改问题较静态查询而言复杂很多,往往需要高级数据结构,可持久化等手段,而静态查询简单很多,例如时间倒流,s之类的方法都是很好的选择
我理解的CDQ分治就是通过离线去掉时间的限制(或者某一维的限制),把动态修改问题转化为静态查询问题...
对于这道题来说,我们可以把查询操作分为4个询问前缀和的操作...
我们把所有的操作按照x排序,那么我们查询的时候维护y的树状数组就可以...这样达到了降维的目的...
我们把操作按照x排序,然后对于当前操作区间[l,r],可以应用分治的思想,把区间按照时间为关键字分为[l,mid]和[mid+1,r]两个区间(在两个区间内x依然有序),对于区间内部的修改操作对查询操作的影响,这是一个相同的子问题,所以我们递归解决即可...我们只需要处理的就是[l,mid]中的修改操作对[mid+1,r]中的查询操作的影响...这个树状数组处理即可...
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 using namespace std; 7 //大鹏一日同风起,扶摇直上九万里 8 9 const int maxn=2000000+5,maxm=200000+5; 10 11 struct M{ 12 int x,y,val,pos,ans; 13 M() {} 14 M(int a,int b,int c,int d); 15 }q[maxm],q2[maxm]; 16 17 int n,m,op,T,tr[maxn],tim[maxn]; 18 19 M :: M(int a=0,int b=0,int c=0,int d=0){ 20 x=a,y=b,val=c,pos=d,ans=0; 21 } 22 23 inline void insert(int x,int y){ 24 for(;x<=n;x+=x&(-x)){ 25 if(tim[x]!=T) 26 tr[x]=0; 27 tim[x]=T,tr[x]+=y; 28 } 29 } 30 31 inline int query(int x){ 32 int res=0; 33 for(;x;x-=x&(-x)) 34 if(tim[x]==T) 35 res+=tr[x]; 36 return res; 37 } 38 39 inline bool cmp1(M a,M b){ 40 return a.x<b.x; 41 } 42 43 inline bool cmp2(M a,M b){ 44 return a.pos<b.pos; 45 } 46 47 inline void CDQ(int l,int r){ 48 if(l==r) 49 return; 50 int mid=(l+r)>>1,l1=l,l2=mid+1; 51 for(int i=l;i<=r;i++){ 52 if(q[i].pos<=mid) 53 q2[l1++]=q[i]; 54 else 55 q2[l2++]=q[i]; 56 } 57 memcpy(q+l,q2+l,sizeof(q[0])*(r-l+1));CDQ(l,mid); 58 int j=l;T++; 59 for(int i=mid+1;i<=r;i++){ 60 for(;q[j].x<=q[i].x&&j<=mid;j++) 61 if(q[j].val!=20010106) 62 insert(q[j].y,q[j].val); 63 if(q[i].val==20010106) 64 q[i].ans+=query(q[i].y); 65 } 66 CDQ(mid+1,r); 67 l1=l,l2=mid+1; 68 for(int i=l;i<=r;i++){ 69 if((q[l1].x<q[l2].x&&l1<=mid)||l2>r) 70 q2[i]=q[l1++]; 71 else 72 q2[i]=q[l2++]; 73 } 74 memcpy(q+l,q2+l,sizeof(q[0])*(r-l+1)); 75 } 76 77 signed main(void){ 78 int l,s,x,y;m=0; 79 scanf("%d%d",&n,&n); 80 while(scanf("%d",&op)&&op!=3){ 81 if(op==1) 82 scanf("%d%d%d",&x,&y,&s),q[++m]=M(x,y,s,m); 83 else 84 scanf("%d%d%d%d",&l,&s,&x,&y), 85 q[++m]=M(l-1,s-1,20010106,m), 86 q[++m]=M(l-1,y ,20010106,m), 87 q[++m]=M(x ,s-1,20010106,m), 88 q[++m]=M(x ,y ,20010106,m); 89 } 90 sort(q+1,q+m+1,cmp1);CDQ(1,m);sort(q+1,q+m+1,cmp2); 91 for(int i=1,lala;i<=m;i++) 92 if(q[i].val==20010106){ 93 lala =q[i++].ans; 94 lala-=q[i++].ans; 95 lala-=q[i++].ans; 96 lala+=q[i ].ans; 97 printf("%d\n",lala); 98 } 99 return 0; 100 }//Cap ou pas cap. Cap.