KD-tree(2维)
用于动态插入以及求某点的最近点的距离(BZOJ2648,BZOJ2716)
#include <cstdio> #include <cmath> #include <algorithm> using namespace std; int cnt,ans,n,m; struct data{ int x,y; }point[500001]; struct kd_node{ int x,y,lc,rc,minx,miny,maxx,maxy; }tr[1000001]; int dis(int x1,int y1,int x2,int y2){ return(fabs(x1-x2)+fabs(y1-y2)); } int mycomp1(const data&a,const data&b){ return(a.y<b.y); } int mycomp2(const data&a,const data&b){ return(a.x<b.x); } void kd_update(int po){ if (tr[po].lc){ tr[po].minx=min(tr[po].minx,tr[tr[po].lc].minx); tr[po].miny=min(tr[po].miny,tr[tr[po].lc].miny); tr[po].maxx=max(tr[po].maxx,tr[tr[po].lc].maxx); tr[po].maxy=max(tr[po].maxy,tr[tr[po].lc].maxy); }; if (tr[po].rc){ tr[po].minx=min(tr[po].minx,tr[tr[po].rc].minx); tr[po].miny=min(tr[po].miny,tr[tr[po].rc].miny); tr[po].maxx=max(tr[po].maxx,tr[tr[po].rc].maxx); tr[po].maxy=max(tr[po].maxy,tr[tr[po].rc].maxy); } }//维护包含子树中所有点的最小的矩形,左下角(minx,miny),右上角(maxx,maxy) void kd_build(int l,int r,int wd){ if (wd) sort(point+l,point+r+1,mycomp1);else sort(point+l,point+r+1,mycomp2);//实际应选取方差最大的一维 cnt++; int mid=(l+r)>>1,t=cnt;//mid实际应为与平均值最接近的 tr[cnt].x=point[mid].x;tr[cnt].y=point[mid].y; tr[cnt].minx=point[mid].x;tr[cnt].maxx=point[mid].x; tr[cnt].miny=point[mid].y;tr[cnt].maxy=point[mid].y; if (l<mid){ tr[t].lc=cnt+1;kd_build(l,mid-1,!wd); }; if (mid<r){ tr[t].rc=cnt+1;kd_build(mid+1,r,!wd); } kd_update(t); }//构建n点的KD树,每次以一维为标准划分点 void kd_ins(int po,int x,int y,int d){ int son=0; if (d==0) son=(x<=tr[po].x);else son=(y<=tr[po].y); if (son==1){ if (tr[po].lc==0){ tr[po].lc=++cnt; tr[cnt].x=x;tr[cnt].y=y; tr[cnt].minx=x;tr[cnt].maxx=x; tr[cnt].miny=y;tr[cnt].maxy=y; }else kd_ins(tr[po].lc,x,y,!d); }else{ if (tr[po].rc==0){ tr[po].rc=++cnt; tr[cnt].x=x;tr[cnt].y=y; tr[cnt].minx=x;tr[cnt].maxx=x; tr[cnt].miny=y;tr[cnt].maxy=y; }else kd_ins(tr[po].rc,x,y,!d); } kd_update(po); } int dist(int x,int y,int po){ int ret=0; ret+=max(0,tr[po].minx-x); ret+=max(0,x-tr[po].maxx); ret+=max(0,tr[po].miny-y); ret+=max(0,y-tr[po].maxy); return(ret); }//(x,y)到po子树维护的矩形的最近距离。假设该矩形中铺满点,所以返回值小于等于实际值 void kd_query(int po,int x,int y){ ans=min(ans,dis(x,y,tr[po].x,tr[po].y)); int dl=(tr[po].lc==0 ? 1e9:dist(x,y,tr[po].lc)); int dr=(tr[po].rc==0 ? 1e9:dist(x,y,tr[po].rc)); if (dl<dr){ if (dl<ans) kd_query(tr[po].lc,x,y); if (dr<ans) kd_query(tr[po].rc,x,y); }else{ if (dr<ans) kd_query(tr[po].rc,x,y); if (dl<ans) kd_query(tr[po].lc,x,y); } }//以dist为估价函数搜寻 int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d%d",&point[i].x,&point[i].y); kd_build(1,n,0); for (int i=1;i<=m;i++){ int opt,x,y; scanf("%d%d%d",&opt,&x,&y); if (opt==1){ kd_ins(1,x,y,0); }else{ ans=1e9; kd_query(1,x,y); printf("%d\n",ans); } } }
____________________________________________
BZOJ4066
单点修改,矩形求和
#include <cstdio> #include <algorithm> #include <iostream> using namespace std; int cnt,tcnt,n; struct data{ int x,y,v; }a[200001]; struct treenode{ int lc,rc,x,y,minx,miny,maxx,maxy,num,v; }tr[200001]; void update(int po){ tr[po].num=tr[tr[po].lc].num+tr[tr[po].rc].num+tr[po].v; tr[po].minx=min(min(tr[tr[po].lc].minx,tr[tr[po].rc].minx),tr[po].x); tr[po].miny=min(min(tr[tr[po].lc].miny,tr[tr[po].rc].miny),tr[po].y); tr[po].maxx=max(max(tr[tr[po].lc].maxx,tr[tr[po].rc].maxx),tr[po].x); tr[po].maxy=max(max(tr[tr[po].lc].maxy,tr[tr[po].rc].maxy),tr[po].y); } void insert(int po,int x,int y,int num,int wd){ if (tr[po].x==x&&tr[po].y==y){ tr[po].num+=num;tr[po].v+=num;return; } int sel; if (!wd) sel=(tr[po].x<x);else sel=(tr[po].y<y); if (!sel){ if (!tr[po].lc){ cnt++; tr[cnt].x=tr[cnt].minx=tr[cnt].maxx=x; tr[cnt].y=tr[cnt].miny=tr[cnt].maxy=y; tr[cnt].v=tr[cnt].num=num; tr[po].lc=cnt; update(po); }else insert(tr[po].lc,x,y,num,!wd); }else{ if (!tr[po].rc){ cnt++; tr[cnt].x=tr[cnt].minx=tr[cnt].maxx=x; tr[cnt].y=tr[cnt].miny=tr[cnt].maxy=y; tr[cnt].v=tr[cnt].num=num; tr[po].rc=cnt; update(po); }else insert(tr[po].rc,x,y,num,!wd); } update(po); } int mycomp1(const data&a,const data&b){ return(a.x<b.x); } int mycomp2(const data&a,const data&b){ return(a.y<b.y); } void build(int l,int r,int wd){ if (wd==0) sort(a+l,a+r+1,mycomp1);else sort(a+l,a+r+1,mycomp2); int mid=(l+r)>>1; int tmp=++tcnt; tr[tcnt].lc=tr[tcnt].rc=0; tr[tcnt].x=a[mid].x;tr[tcnt].y=a[mid].y;tr[tcnt].v=a[mid].v; if (l<mid){ tr[tmp].lc=tcnt+1;build(l,mid-1,!wd); }; if (r>mid){ tr[tmp].rc=tcnt+1;build(mid+1,r,!wd); } update(tmp); } int in(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2){ return(X1<=x1&&Y1<=y1&&X2>=x2&&Y2>=y2); } int out(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2){ return(x2<X1||x1>X2||y1>Y2||y2<Y1); } int query(int po,int x1,int y1,int x2,int y2){ int ret=0; if (in(tr[po].minx,tr[po].miny,tr[po].maxx,tr[po].maxy,x1,y1,x2,y2)) return(tr[po].num); if (in(tr[po].x,tr[po].y,tr[po].x,tr[po].y,x1,y1,x2,y2)) ret+=tr[po].v; if (!out(tr[tr[po].lc].minx,tr[tr[po].lc].miny,tr[tr[po].lc].maxx,tr[tr[po].lc].maxy,x1,y1,x2,y2)) ret+=query(tr[po].lc,x1,y1,x2,y2); if (!out(tr[tr[po].rc].minx,tr[tr[po].rc].miny,tr[tr[po].rc].maxx,tr[tr[po].rc].maxy,x1,y1,x2,y2)) ret+=query(tr[po].rc,x1,y1,x2,y2); return(ret); } int main(){ scanf("%d",&n); tr[0].miny=tr[0].minx=1e9; tr[0].maxx=tr[0].maxy=-1e9; int opt,lastans=0,lastrebuild=0,root=0; while (scanf("%d",&opt),opt!=3){ int x,y,x1,y1,x2,y2,num; if (opt==1){ scanf("%d%d%d",&x,&y,&num); x^=lastans;y^=lastans;num^=lastans; if (!root){ root=1; cnt++; tr[cnt].x=tr[cnt].minx=tr[cnt].maxx=x; tr[cnt].y=tr[cnt].miny=tr[cnt].maxy=y; tr[cnt].v=tr[cnt].num=num; }else{ insert(root,x,y,num,0); } if (cnt/10000>lastrebuild){ for (int i=1;i<=cnt;i++) a[i].x=tr[i].x,a[i].y=tr[i].y,a[i].v=tr[i].v; tcnt=0; build(1,cnt,0); lastrebuild++; } } if (opt==2){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); x1^=lastans;x2^=lastans;y1^=lastans;y2^=lastans; lastans=query(1,x1,y1,x2,y2); printf("%d\n",lastans); } } }