2683: 简单题
Description
你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
①
读入:1 x y A
1<=x,y<=N,A是正整数
将格子x,y里的数字加上A
②
读入:2 x1 y1 x2 y2
1<=x1<= x2<=N
1<=y1<= y2<=N
输出x1 y1 x2 y2这个矩形内的数字和
③
读入:3
终止程序
Input
输入文件第一行一个正整数N。
接下来每行一个操作。
Output
对于每个2操作,输出一个对应的答案。
Sample Input
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
1<=N<=500000,操作数不超过200000个,内存限制20M。
对于100%的数据,操作1中的A不超过2000。
ps:1176只是多了个初始值~
分析:
看到数据范围,就知道二维树状数组不行。
于是想如何就二维转化为一维。便想到了CDQ分治~~
考虑把
(x1,y1)(x1,y1)
到
(x2,y2)(x2,y2)
的矩阵拆成
(x1−1,y1−1)
,
(x1−1,y2)
,
(x2,y1−1)
,
(x2,y2)
然后容斥原理搞搞就行了。
矩阵拆开后和操作1一起按插入时间排序。
然后二分时间,因为分治的左区间对右区间有贡献于是将右区间所有操作1搞到树状数组中,左区间的询问操作进行统计。
再用O(r-l+1)的时间将数组按时间(与mid比较)分成左右两部分
继续向下递归。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=800100;
int n,m,tot,ans[N],w,x1,yy1,x2,y2,k,c[N],cnt;
struct node{int x,y,id,op,z,c;}g[N],t[N];
int cmp(node a,node b)
{
if (a.x!=b.x) return a.x<b.x;
if (a.y!=b.y) return a.y<b.y;
return a.id<b.id;
}
void ins(int x,int val)
{
while (x<=n)
{
c[x]+=val;
x+=x&-x;
}
}
int query(int x)
{
int res=0;
while (x)
{
res+=c[x];
x-=x&-x;
}
return res;
}
void cdq(int l,int r)
{
if (l==r) return;
int mid=(l+r)/2;
for (int i=l;i<=r;i++)
{
if (g[i].op==1 && g[i].id<=mid) ins(g[i].y,g[i].z);
if (g[i].op==2 && g[i].id>mid) ans[g[i].c]+=g[i].z*query(g[i].y);
}
for (int i=l;i<=r;i++)
if (g[i].op==1 && g[i].id<=mid)
ins(g[i].y,-g[i].z);
int l1=l,l2=mid+1;
for (int i=l;i<=r;i++)
if (g[i].id<=mid)
t[l1++]=g[i]; else
t[l2++]=g[i];
for (int i=l;i<=r;i++)
g[i]=t[i];
cdq(l,mid);cdq(mid+1,r);
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d",&w,&n);
while (1)
{
scanf("%d",&k);
if (k==3) break;
int t;
if (k==1)
{
scanf("%d%d%d",&x1,&yy1,&t);
g[++tot].x=x1;
g[tot].y=yy1;
g[tot].z=t;
g[tot].op=1;
g[tot].id=tot;
} else
{
scanf("%d%d%d%d",&x1,&yy1,&x2,&y2);
ans[++cnt]=(x2-x1+1)*(y2-yy1+1)*w;
g[++tot].x=x1-1;g[tot].y=yy1-1;g[tot].op=2;g[tot].z=1;g[tot].c=cnt;g[tot].id=tot;
g[++tot].x=x2;g[tot].y=y2;g[tot].op=2;g[tot].z=1;g[tot].c=cnt;g[tot].id=tot;
g[++tot].x=x1-1;g[tot].y=y2;g[tot].op=2;g[tot].z=-1;g[tot].c=cnt;g[tot].id=tot;
g[++tot].x=x2;g[tot].y=yy1-1;g[tot].op=2;g[tot].z=-1;g[tot].c=cnt;g[tot].id=tot;
}
}
sort(g+1,g+tot+1,cmp);
cdq(1,tot);
for (int i=1;i<=cnt;i++)
printf("%d\n",ans[i]);
}