BZOJ1176: [Balkan2007]Mokia(CDQ+树状数组)
题意:N*N的矩形 N<=2e6 操作一 单点更新 操作二 查询矩形区域和 我们用三元组(t,x,y)表示第x操作作用(x,y)坐标 然后对于询问拆成四个答案维护即可 跑CDQ把每部分的答案综合起来即可!
#include <bits/stdc++.h> #define ll long long const int NM=2e6+10; const int nm=2e5+10; using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } typedef struct node{ int x,y;int pos,vul; }node; node d[nm];ll ans[nm]; node q[nm]; int n,cnt; int p[NM]; int get_id(int x){return x&(-x);} void update(int x,int vul){ if(!x||!vul)return ; for(int i=x;i<=n;i+=get_id(i))p[i]+=vul; } int Sum(int x){ int sum=0; for(int i=x;i>0;i-=get_id(i))sum+=p[i]; return sum; } void clear(int x){ if(!x)return ; for(int i=x;i<=n;i+=get_id(i))p[i]=0; } void gui(int l,int mid,int r){ // cout<<l<<" "<<mid<<" "<<r<<endl; int i=l;int j=mid+1;int num=0; while(i<=mid&&j<=r){ while(i<=mid&&d[i].x<=d[j].x)q[++num]=d[i],update(d[i].y,d[i].vul),i++; q[++num]=d[j]; // cout<<num<<"---==="<<d[j].y<<endl; // update(d[j].y,d[j].vul); if(d[j].pos<0){ans[d[j].pos*-1]-=Sum(d[j].y);} else if(d[j].pos>0){ans[d[j].pos]+=Sum(d[j].y);} j++; // cout<<num<<endl; } if(i<=mid)while(i<=mid)q[++num]=d[i],update(d[i].y,d[i].vul),i++; if(j<=r){ while(j<=r){ q[++num]=d[j]; // update(d[j].y,d[j].vul); if(d[j].pos<0){ans[d[j].pos*-1]-=Sum(d[j].y);} else if(d[j].pos>0){ans[d[j].pos]+=Sum(d[j].y);} j++; } } for(int k=1;k<=num;k++)d[l+k-1]=q[k],clear(q[k].y); } void cdq(int l,int r){ if(l>=r)return ; // cout<<l<<" "<<r<<endl; int mid=(l+r)>>1; cdq(l,mid); cdq(mid+1,r); gui(l,mid,r); //cout<<l<<"--==="<<r<<endl; //for(int i=l;i<=r;i++)cout<<d[i].x<<" "<<d[i].y<<endl; // cout<<l<<" "<<r<<endl; } int main(){ int s;s=read();n=read(); int op;int x,y,x1,y1; while(op=read()){ if(op==3)break; if(op==1)d[++cnt].x=read(),d[cnt].y=read(),d[cnt].vul=read(),d[cnt].pos=0,ans[cnt]=-1; else{ x=read();y=read();x1=read();y1=read(); d[++cnt].x=x-1;d[cnt].y=y-1;d[cnt].pos=cnt;ans[cnt]=1ll*x*y*s; int t1=cnt; d[++cnt].x=x-1;d[cnt].y=y1;d[cnt].pos=-1*t1;ans[t1]-=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1; d[++cnt].x=x1;d[cnt].y=y-1;d[cnt].pos=-1*t1;ans[t1]-=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1; d[++cnt].x=x1;d[cnt].y=y1;d[cnt].pos=t1;ans[t1]+=1ll*d[cnt].x*d[cnt].y*s;ans[cnt]=-1; //cout<<ans[t1]<<endl; } } //cout<<cnt<<endl; cdq(1,cnt); for(int i=1;i<=cnt;i++)if(ans[i]>=0)printf("%lld\n",ans[i]); }
1176: [Balkan2007]Mokia
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 3265 Solved: 1460
[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
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
3
5
5
HINT
保证答案不会超过int范围