2683: 简单题
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 1613 Solved: 651
[ Submit][ Status][ Discuss]
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
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
1<=N<=500000,操作数不超过200000个,内存限制20M。
对于100%的数据,操作1中的A不超过2000。
Source
题解:像这种题第一感觉是二维树状数组,然而n有100000,开不了这么大的数组。
当然,kd树也是可以的,然而我并不会,这里采用一种新姿势:CDQ分治。
看了许多博客和PPT,算是懂的差不多了,看完各种大佬们的讲解,发现cdq分治怎么
和归并排序这么像? 以为是自己yy,其实就是这样。归并排序就是一种简单的cdq分治。
呢就讲一下cdq分治喽。
一篇关于cdq分治的很好的讲解博客:http://www.cnblogs.com/mlystdcall/p/6219421.html
CDQ分治:
优点:可以顶替复杂的高级数据结构,而且常数比较小
缺点:必须离线操作
基本思想:将查询和修改看做整体,然后对其排序,设这个整体的区间是[l,r],然后我们
可以将问题进行分治,比如分成区间[l,m]和[m+1,r]。这样一个主问题就分解成两个子问题了,
但是你会有疑问了,呢前半部分区间对后半部分区间产生影响怎么办? 没错,这就是cdq分治和
普通分治最根本的区别所在。分治的区间是会相互影响的(当然后边不会影响前边的)。
说白了cdq分治就是将一个问题分解成两个子问题,然后枚举前半区间对后半区间的影响,之后
通过递归在分别仿照之前求解若干子区间的过程(当然你可以从小到大递归)。
(可能说的不是很对,我是这样理解的)
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<time.h>
#include<math.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<functional>
using namespace std;
#define ll long long
#define inf 1000000000
#define mod 1000000007
#define maxn 100010
#define lowbit(x) (x&-x)
#define eps 1e-9
struct node
{
int x,y,id,xd,siz,val;
bool operator <(const node &b) const
{
if(x<b.x || x==b.x && y<b.y || x==b.x && y==b.y && siz<b.siz)
return 1;
return 0;
}
}q[maxn*8],a[maxn*8];
int n,ans[maxn*8],num,sum[maxn*8];
void update(int x,int val)
{
while(x<=n)
{
sum[x]+=val;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x)
{
res+=sum[x];
x-=lowbit(x);
}
return res;
}
void cdq(int l,int r)
{
if(l==r)
return;
int i,m=(l+r)/2;
for(i=l;i<=r;i++)
{
if(a[i].siz==1 && a[i].id<=m)
update(a[i].y,a[i].val);
if(a[i].siz==2 && a[i].id>m)
ans[a[i].xd]+=query(a[i].y)*a[i].val;
}
for(i=l;i<=r;i++)
if(a[i].siz==1 && a[i].id<=m)
update(a[i].y,-a[i].val);
int lq=l,rq=m+1;
for(i=l;i<=r;i++)
{
if(a[i].id<=m)
q[lq++]=a[i];
else
q[rq++]=a[i];
}
for(i=l;i<=r;i++)
a[i]=q[i];
cdq(l,m);cdq(m+1,r);
}
int main(void)
{
int i,j,cnt=0,t,x,y,xx,yy,z;
scanf("%d",&n);
while(1)
{
scanf("%d",&t);
if(t==1)
{
scanf("%d%d%d",&x,&y,&z);
a[++num].x=x;a[num].y=y;a[num].val=z;a[num].id=num;a[num].siz=1;
}
else if(t==2)
{
scanf("%d%d%d%d",&x,&y,&xx,&yy);
a[++num].x=x-1;a[num].y=y-1;a[num].val=1;a[num].id=num;a[num].xd=++cnt;a[num].siz=2;
a[++num].x=xx;a[num].y=yy;a[num].val=1;a[num].id=num;a[num].xd=cnt;a[num].siz=2;
a[++num].x=x-1;a[num].y=yy;a[num].val=-1;a[num].id=num;a[num].xd=cnt;a[num].siz=2;
a[++num].x=xx;a[num].y=y-1;a[num].val=-1;a[num].id=num;a[num].xd=cnt;a[num].siz=2;
}
else
break;
}
sort(a+1,a+num+1);
cdq(1,num);
for(i=1;i<=cnt;i++)
printf("%d\n",ans[i]);
return 0;
}