题目大意:
你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
题目分析:(CDQ分治)
借鉴自YihAN_Z的博客
CDQ分治的主要思想是按照时间进行分治。
首先把一个询问拆成4个,把所有的点按照x坐标进行排序,然后在处理的区间内把时间小于等于mid的扔到左边,时间大于mid的扔到右边,这是x坐标在左右区间还是有序的,然后我们处理左区间的修改对右区间询问的影响。
并且递归处理左区间和右区间。
个人感觉整个过程就像是有一个按照时间排好序的序列,然后你把这个序列按照x坐标打乱,然后在CDQ的过程中就像是再按照时间关键字重新做一遍归并排序(当然CDQ分治最后还要把这个序列还原,相当于没排……),然后在这个过程中处理出答案。
此题用CDQ分治的好处就是降了一维,省空间,时间上如果n和m差距不是很大,应该是差不多的。
二维树状数组:空间O(n^2) 时间 O (m * logn * logn)
CDQ分治: 空间O(n) 时间 O(m * logm * logn)
可以看出CDQ分治的优越性。
以下是bzoj2683的代码,bzoj1176同此题,所有处理都是一样的,只不过在最后计算答案的时候加上初始的s乘以询问矩阵的大小再输出就可以了(那个初始的s就是来打个酱油,真的没什么大用)。
代码如下(↓今天代码不知为何奇丑无比):
#include<cstdio>
#include<algorithm>
#define N 520000
#define M 220000
using namespace std;
struct operation{
int x,y,mode,tim,ans;
operation(){}
operation(int x,int y,int mode,int tim,int ans):x(x),y(y),mode(mode),tim(tim),ans(ans){}
bool operator < (const operation &c) const { return x<c.x; }
}q[M*4],tmp[M*4];
int n,opt,x,y,x1,y1,x2,y2,z,top,timestamp;
int c[N],d[N];
bool cmp (operation a,operation b) {return a.tim<b.tim;}
int lowbit(int x) {return x&-x;}
void change(int x,int v)
{
for(;x<=n;x+=lowbit(x))
{
if(d[x]!=timestamp) c[x]=0,d[x]=timestamp;
c[x]+=v;
}
return;
}
int query(int x)
{
int ans=0;
for(;x;x-=lowbit(x)) if(d[x]==timestamp) ans+=c[x];
return ans;
}
void CDQ(int l,int r)
{
if(l==r) return;
int mid=l+r>>1;
int l1=l,l2=mid+1;
for(int i=l;i<=r;i++)
if(q[i].tim<=mid) tmp[l1++]=q[i];
else tmp[l2++]=q[i];
for(int i=l;i<=r;i++) q[i]=tmp[i];
CDQ(mid+1,r); CDQ(l,mid);
l1=l; l2=mid+1; timestamp++;
for(;l2<=r;l2++)
{
for(;q[l1].x<=q[l2].x && l1<=mid;l1++)
if(q[l1].mode==1) change(q[l1].y,q[l1].ans);
if(q[l2].mode==2) q[l2].ans+=query(q[l2].y);
}
l1=l; l2=mid+1;
for(int i=l;i<=r;i++)
if(q[l1]<q[l2] && l1<=mid || l2>r) tmp[i]=q[l1++];
else tmp[i]=q[l2++];
for(int i=l;i<=r;i++) q[i]=tmp[i];
return;
}
int main()
{
scanf("%d",&n);
while(scanf("%d",&opt)!=EOF)
{
if(opt==3) break;
if(opt==1)
{
scanf("%d%d%d",&x,&y,&z);
q[++top]=operation(x,y,1,top,z);
}
else
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
q[++top]=operation(x1-1,y1-1,2,top,0);
q[++top]=operation(x1-1, y2,2,top,0);
q[++top]=operation( x2,y1-1,2,top,0);
q[++top]=operation( x2, y2,2,top,0);
}
}
sort(q+1,q+1+top);
CDQ(1,top);
sort(q+1,q+1+top,cmp);
for(int i=1;i<=top;i++)
if(q[i].mode==2)
{
int ans=0;
ans+=q[i++].ans;
ans-=q[i++].ans;
ans-=q[i++].ans;
ans+=q[i ].ans;
printf("%d\n",ans);
}
return 0;
}