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
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3
Sample Output
3
5
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)); } } }