P4148 简单题 KDTree
KDtree模板题
不会的看这里
本题离线的话就是裸的cdq分治
强制在线那就按维分割,加入新点的话类似于建树过程,同时记录一下点的范围,以便询问的时候好剪枝
为了防止出题人毒瘤(比如让你建的树成了一条链),你可以每过一段时间重构一下这棵树。
代码虽长,但很好写
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int d,root;
const int N=490001;
struct data
{
int p[2],maxn[2],minn[2],c[2],w,sum;
}a[N];
bool cmp(data a,data b)
{
return a.p[d]==b.p[d]?a.p[d^1]<b.p[d^1]:a.p[d]<b.p[d];
}
void pushup(int k,int s)
{
a[k].maxn[0]=max(a[k].maxn[0],a[s].maxn[0]);
a[k].minn[0]=min(a[k].minn[0],a[s].minn[0]);
a[k].maxn[1]=max(a[k].maxn[1],a[s].maxn[1]);
a[k].minn[1]=min(a[k].minn[1],a[s].minn[1]);
a[k].sum+=a[s].sum;
}
int build(int l,int r,int now)
{
int mid=(l+r)>>1;d=now;
nth_element(a+l,a+mid,a+1+r,cmp);
a[mid].maxn[0]=a[mid].minn[0]=a[mid].p[0];
a[mid].maxn[1]=a[mid].minn[1]=a[mid].p[1];
a[mid].sum=a[mid].w;
a[mid].c[0]=a[mid].c[1]=0;
if(l<mid)a[mid].c[0]=build(l,mid-1,now^1),pushup(mid,a[mid].c[0]);
if(r>mid)a[mid].c[1]=build(mid+1,r,now^1),pushup(mid,a[mid].c[1]);
return mid;
}
void Insert(int x)
{
int *t=&root;d=0;
while(*t)pushup(*t,x),t=&a[*t].c[a[x].p[d]>a[*t].p[d]],d^=1;
*t=x;
}
int query(int k,int x1,int y1,int x2,int y2)
{
if(!k||a[k].maxn[0]<x1||x2<a[k].minn[0]||a[k].maxn[1]<y1||y2<a[k].minn[1])return 0;
if(x1<=a[k].minn[0]&&a[k].maxn[0]<=x2&&y1<=a[k].minn[1]&&a[k].maxn[1]<=y2)return a[k].sum;
int ans=0;
if(x1<=a[k].p[0]&&a[k].p[0]<=x2&&y1<=a[k].p[1]&&a[k].p[1]<=y2)ans+=a[k].w;
ans+=query(a[k].c[0],x1,y1,x2,y2)+query(a[k].c[1],x1,y1,x2,y2);
return ans;
}
int main()
{
int opt,x1,y1,x2,y2,last=0,tot=0;
scanf("%*d");
while(scanf("%d",&opt)!=EOF&&opt!=3)
{
if(opt==1)
{
++tot,scanf("%d%d%d",&a[tot].p[0],&a[tot].p[1],&a[tot].w);
a[tot].p[0]^=last,a[tot].p[1]^=last,a[tot].w^=last,a[tot].sum=a[tot].w;
a[tot].maxn[0]=a[tot].minn[0]=a[tot].p[0];
a[tot].maxn[1]=a[tot].minn[1]=a[tot].p[1];
Insert(tot);
if(tot%10000==0)root=build(1,tot,0);
}
else scanf("%d%d%d%d",&x1,&y1,&x2,&y2),x1^=last,y1^=last,x2^=last,y2^=last,printf("%d\n",last=query(root,x1,y1,x2,y2));
}
return 0;
}