Time Limit: 30 Sec Memory Limit: 162 MB
Submit: 1605 Solved: 697
[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
0 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
保证答案不会超过int范围
Source
Sol:
体会到了CDQ分治的强大,强行把复杂度降到log
也是一道论文题,用到了上一篇博文打的离散化树状数组,建议做这题前做一下传送门
离散化x,递归处理左子树,在右子树中加入左子树的贡献,清空左子树做出的贡献,直接memset不太好就改造一下树状数组,写一个标记即可。
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
#define N 200005
#define W 2000005
inline int in(int x=0,int v=1,char ch=getchar()){while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
if(ch=='-') v=-1,ch=getchar();while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*v;}
struct Point{int x,y,k,v,f,s,id;}q[N],tmp[N];
int s,w,cnt,tot,deep;int ans[N];int d[W],g[W];
inline bool operator < (const Point &a,const Point &b){return a.x<b.x||(a.x==b.x&&a.id<b.id);}
inline void Add(int x,int v){for(;x<=w;x+=x&-x){if(g[x]!=deep) g[x]=deep,d[x]=0;d[x]+=v;}}
inline int Sum(int x,int res=0){for(;x;x-=x&-x) if(g[x]==deep) res+=d[x];return res;}
void Solve(int l,int r){
if(l==r) return;
int mid=(l+r)>>1,h=l,t=mid+1;
for(int i=l;i<=r;i++) if(q[i].id<=mid) tmp[h++]=q[i];else tmp[t++]=q[i];
for(int i=l;i<=r;i++) q[i]=tmp[i];
Solve(l,mid);deep++;
for(int i=mid+1,j=l;i<=r;i++){
for(;j<=mid&&q[j].x<=q[i].x;j++) if(q[j].k==1) Add(q[j].y,q[j].v);
if(q[i].k==2) ans[q[i].s]+=Sum(q[i].y)*q[i].f;
}
Solve(mid+1,r);h=l,t=mid+1;
for(int i=l;i<=r;i++){
if(t>r||(h<=mid&&q[h].x<=q[t].x)) tmp[i]=q[h++];
else tmp[i]=q[t++];
}
for(int i=l;i<=r;i++) q[i]=tmp[i];
}
int main(){
s=in(),w=in();int k,a,b,x,y;
for(;;){
k=in();if(k==3) break;
if(k==1) x=in(),y=in(),a=in(),q[++tot]=(Point){x,y,k,a,0,0,tot};
if(k==2)
a=in(),b=in(),x=in(),y=in(),
q[++tot]=(Point){a-1,b-1,k,0,1,++cnt,tot},
q[++tot]=(Point){a-1,y,k,0,-1,cnt,tot},
q[++tot]=(Point){x,b-1,k,0,-1,cnt,tot},
q[++tot]=(Point){x,y,k,0,1,cnt,tot},
ans[cnt]+=(x-a+1)*(y-b+1)*s;
}
sort(q+1,q+tot+1);Solve(1,tot);
for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
return 0;
}