[BZOJ1176]Mokia
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
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
3
5
5
时隔五个月再做这道题又有新的理解
首先把操作看成四个二维前缀和相加减,然后对于每个操作有三个维度:时间,$x$轴,$y$轴
考虑对一个查询,哪些修改操作会对它产生影响,当且仅当在它之前发生且在它的左下方
所以我们可以按照$x$轴先排序消除$x$轴的影响
然后对归并排序时间戳使得左右两部分的操作有序
然后按时间戳加入修改和询问就完成了
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define M 2000010 6 using namespace std; 7 int read() { 8 char ch=getchar();int x=0; 9 while(ch>'9'||ch<'0') ch=getchar(); 10 while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); 11 return x; 12 } 13 int n,S,tot,qcnt,tim; 14 int ans[M],f[M]; 15 struct ASK{int t,x,y,w,ot,id;}q[M],tmp[M]; 16 bool cmp(ASK a1,ASK a2) { 17 if(a1.x!=a2.x) return a1.x<a2.x; 18 if(a1.y!=a2.y) return a1.y<a2.y; 19 return a1.id<a2.id; 20 } 21 void add(int loc,int v) { 22 for(int i=loc;i<=n;i+=(i&-i)) f[i]+=v; 23 } 24 int query(int loc) { 25 int ans=0; 26 for(int i=loc;i;i-=(i&-i)) ans+=f[i]; 27 return ans; 28 } 29 void CDQ(int l,int r) { 30 if(l==r) return; 31 int mid=(l+r)>>1; 32 CDQ(l,mid);CDQ(mid+1,r); 33 int t1=l,t2=mid+1,now=l; 34 while(t1<=mid||t2<=r) { 35 if(t1<=mid&&q[t1].t<q[t2].t||t2>r) { 36 if(q[t1].ot==1) add(q[t1].y,q[t1].w); 37 tmp[now++]=q[t1++]; 38 } 39 else { 40 if(q[t2].ot==2) ans[q[t2].id]+=q[t2].w*query(q[t2].y); 41 tmp[now++]=q[t2++]; 42 } 43 } 44 for(int i=l;i<=mid;i++) 45 if(q[i].ot==1) 46 add(q[i].y,-q[i].w); 47 for(int i=l;i<=r;i++) q[i]=tmp[i]; 48 } 49 int main() { 50 S=read();n=read(); 51 while(1) { 52 int opt=read(); 53 if(opt==3) break; 54 if(opt==1) { 55 int x=read(),y=read(),z=read(); 56 q[++tot]=(ASK){++tim,x,y,z,1}; 57 } 58 else { 59 int x1=read(),y1=read(),x2=read(),y2=read(); 60 ans[++qcnt]=(x2-x1+1)*(y2-y1+1)*S; 61 q[++tot]=(ASK){++tim,x1-1,y1-1,1,2,qcnt}; 62 q[++tot]=(ASK){++tim,x2,y2,1,2,qcnt}; 63 q[++tot]=(ASK){++tim,x1-1,y2,-1,2,qcnt}; 64 q[++tot]=(ASK){++tim,x2,y1-1,-1,2,qcnt}; 65 } 66 } 67 sort(q+1,q+1+tot,cmp); 68 CDQ(1,tot); 69 for(int i=1;i<=qcnt;i++) printf("%d\n",ans[i]); 70 return 0; 71 }