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范围

浙公网安备 33010602011771号