BZOJ_4066_简单题_KDtree

BZOJ_4066_简单题_KDtree

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。
接下来每行一个操作。每条命令除第一个数字之外,
均要异或上一次输出的答案last_ans,初始时last_ans=0。

Output

对于每个2操作,输出一个对应的答案。

Sample Input

4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3

Sample Output

3
5

HINT

数据规模和约定
1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。

离线可以CDQ分治做。
这题强制在线,那么用KDTree处理矩形查询问题。
每个节点维护矩形点权和即可,查询时如果当前矩形被包含了就返回这个值,然后递归左右子树。
插入点数太多会导致KDTree的结构退化,于是需要重构。
 
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 200050
#define FAC 0.75
#define ls ch[p][0]
#define rs ch[p][1]
#define _max(x,y) ((x)>(y)?(x):(y))
#define _min(x,y) ((x)<(y)?(x):(y))
int ch[N][2],sum[N],mx[N][2],mn[N][2],now,root,dep[N],n;
struct Point {
	int p[2],v;
	bool operator < (const Point &x) const {
		return p[now]==x.p[now]?p[!now]<x.p[!now]:p[now]<x.p[now];
	}
}a[N];
inline char nc() {
	static char buf[100000],*p1,*p2;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rd() {
	int x=0; char s=nc();
	while(s<'0'||s>'9') s=nc();
	while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
	return x;
}
void pushup(int p,int x) {
	mx[p][0]=_max(mx[p][0],mx[x][0]);
	mn[p][0]=_min(mn[p][0],mn[x][0]);
	mx[p][1]=_max(mx[p][1],mx[x][1]);
	mn[p][1]=_min(mn[p][1],mn[x][1]);
	sum[p]+=sum[x];
}
int build(int l,int r,int type) {
	int mid=(l+r)>>1; now=type;
	nth_element(a+l,a+mid,a+r+1);
	mx[mid][0]=mn[mid][0]=a[mid].p[0];
	mx[mid][1]=mn[mid][1]=a[mid].p[1];
	sum[mid]=a[mid].v;
	ch[mid][0]=ch[mid][1]=0;
	if(l<mid) ch[mid][0]=build(l,mid-1,!type),pushup(mid,ch[mid][0]);
	if(r>mid) ch[mid][1]=build(mid+1,r,!type),pushup(mid,ch[mid][1]);
	return mid;
}
void insert(int x) {
	int p=root;
	mx[x][0]=mn[x][0]=a[x].p[0];
	mx[x][1]=mn[x][1]=a[x].p[1];
	sum[x]=a[x].v;
	if(!p) {root=x; return ;}
	now=0;
	while(1) {
		pushup(p,x);
		if(a[x]<a[p]) {
			if(ls) p=ls;
			else {ls=x; return ;}
		}else {
			if(rs) p=rs;
			else {rs=x; return ;}
		}
		now^=1;
	}
}
int query(int x,int y,int z,int w,int p) {
	if(mn[p][0]>=x&&mx[p][0]<=z&&mn[p][1]>=y&&mx[p][1]<=w) return sum[p];
	int re=0;
	if(a[p].p[0]<=z&&a[p].p[0]>=x&&a[p].p[1]<=w&&a[p].p[1]>=y) re+=a[p].v;
	if(ls&&mn[ls][0]<=z&&mx[ls][0]>=x&&mn[ls][1]<=w&&mx[ls][1]>=y) re+=query(x,y,z,w,ls);
	if(rs&&mn[rs][0]<=z&&mx[rs][0]>=x&&mn[rs][1]<=w&&mx[rs][1]>=y) re+=query(x,y,z,w,rs);
	return re;
}
int main() {
	rd();
	int opt,x,y,z,w,ans=0;
	while(1) {
		opt=rd();
		if(opt==3) break;
		if(opt==1) {
			n++;
			x=rd(); y=rd(); z=rd();
			a[n].p[0]=x^ans;
			a[n].p[1]=y^ans;
			a[n].v=z^ans;
			insert(n);
			if(n%10000==0) root=build(1,n,0);
		}else {
			x=rd(); y=rd(); z=rd(); w=rd();
			x^=ans; y^=ans; z^=ans; w^=ans;
			printf("%d\n",ans=query(x,y,z,w,root));
		}
	}
}

 

posted @ 2018-07-08 06:59  fcwww  阅读(329)  评论(0编辑  收藏  举报