[清橙A1365]森林旅店【KD-tree】
【题目描述】
试题来源
清华大学2012年信息学优秀高中学子夏令营
问题描述
小H家旁边的树林可是一年四季度假的好地方。为了整合资源扩大效益,小H打算在树林中建立一些“泰山的小屋”,即在一些树木上建造一些小屋,让大家更加近距离地体会自然的美。
不过有一个问题一直困扰着小H的计划,那就是森林中白蚁泛滥。大家都知道白蚁对于树木和木制品的危害,如果建造的房子周围白蚁成灾,那无疑就是将游客的人身安全置于一个危险的境地中了。因此小H在建造小屋的时候必须更加合理地考量房子的安全性。
简而言之,我们可以认为森林里有许多的树木,其中有N个白蚁穴在这些树木上。在同一棵树上最多只有一个白蚁穴。
小H想知道,如果他希望在某棵树上建立一座小屋,那么周围离它最近的P 个白蚁穴的距离分别是多少呢?
同时由于随时可能发现新的白蚁穴,你的程序还应该支持动态地加入新发现的蚁穴。
不过有一个问题一直困扰着小H的计划,那就是森林中白蚁泛滥。大家都知道白蚁对于树木和木制品的危害,如果建造的房子周围白蚁成灾,那无疑就是将游客的人身安全置于一个危险的境地中了。因此小H在建造小屋的时候必须更加合理地考量房子的安全性。
简而言之,我们可以认为森林里有许多的树木,其中有N个白蚁穴在这些树木上。在同一棵树上最多只有一个白蚁穴。
小H想知道,如果他希望在某棵树上建立一座小屋,那么周围离它最近的P 个白蚁穴的距离分别是多少呢?
同时由于随时可能发现新的白蚁穴,你的程序还应该支持动态地加入新发现的蚁穴。
输入格式
第一行包含四个整数N,Q,K和P。 N为初始时的白蚁穴数量,Q是操作数量,K是距离度量函数的参数,P为每次查询要输出的蚁穴个数。
对于坐标位置为(X_1,Y_1 )和(X_2,Y_2 )的距离,我们定义为:
(|X_1-X_2 |^K + |Y_1-Y_2 |^K )^(1/K)
接下来N行,每行两个整数,表示初始时白蚁穴的坐标。
再接下来Q行,每行有一个字符C和两个整数X和Y。字符C是‘A’表示加入一个坐标为(X,Y)的白蚁穴,‘Q’表示询问如果在(X,Y)建造一个小屋,请告知周边的蚁穴情况。
对于坐标位置为(X_1,Y_1 )和(X_2,Y_2 )的距离,我们定义为:
(|X_1-X_2 |^K + |Y_1-Y_2 |^K )^(1/K)
接下来N行,每行两个整数,表示初始时白蚁穴的坐标。
再接下来Q行,每行有一个字符C和两个整数X和Y。字符C是‘A’表示加入一个坐标为(X,Y)的白蚁穴,‘Q’表示询问如果在(X,Y)建造一个小屋,请告知周边的蚁穴情况。
输出格式
对于每组询问,输出P 个实数,以单个空格隔开,表示距离最近的 个蚁穴的距离,精确到小数点后4位。
样例输入
1 3 1 1
0 0
Q 0 2
A 0 3
Q 0 2
0 0
Q 0 2
A 0 3
Q 0 2
样例输出
2.0000
1.0000
1.0000
数据规模和约定
本题的测试数据均以以下方式生成。
假设所有出现的蚁穴是:{(X_i,Y_i )}, 1≤i≤M。设函数f(x), g(x)是两个单调函数。数据生成方法如下:
1.生成M个随机点(x_i,y_i),满足0≤ x_i,y_i≤1;
2.最终输入数据为X_i=f(x_i ),Y_i=g(y_i ),且满足0≤ X_i,Y_i≤10^7。
测试数据共分10组,每组包括5个测试点,共50个测试点。同一组的5个测试数据的蚁穴的初始位置由同一组随机点经不同的函数变换产生。
测试数据组 1 2 3 4 5
N 5,000 20,000 100,000 100,000 20,000
Q 2,000 10,000 5,000 20,000 2,000
K 1 1 1 1 2
P 1 3 3 3 1
测试数据组 6 7 8 9 10
N 20,000 100,000 100,000 100,000 100,000
Q 20,000 5,000 20,000 20,000 20,000
K 2 2 2 2 2
P 3 3 3 3 3
表中所有数据均为数据上界。
每组测试点集合中 的数据不包含插入操作。
所有数据中查询次数不超过5,000次。
假设所有出现的蚁穴是:{(X_i,Y_i )}, 1≤i≤M。设函数f(x), g(x)是两个单调函数。数据生成方法如下:
1.生成M个随机点(x_i,y_i),满足0≤ x_i,y_i≤1;
2.最终输入数据为X_i=f(x_i ),Y_i=g(y_i ),且满足0≤ X_i,Y_i≤10^7。
测试数据共分10组,每组包括5个测试点,共50个测试点。同一组的5个测试数据的蚁穴的初始位置由同一组随机点经不同的函数变换产生。
测试数据组 1 2 3 4 5
N 5,000 20,000 100,000 100,000 20,000
Q 2,000 10,000 5,000 20,000 2,000
K 1 1 1 1 2
P 1 3 3 3 1
测试数据组 6 7 8 9 10
N 20,000 100,000 100,000 100,000 100,000
Q 20,000 5,000 20,000 20,000 20,000
K 2 2 2 2 2
P 3 3 3 3 3
表中所有数据均为数据上界。
每组测试点集合中 的数据不包含插入操作。
所有数据中查询次数不超过5,000次。
清华夏令营竟有模板题。。。
KD-tree裸题,分别处理k=1,2的情况。
# include <bits/stdc++.h> # define N 300010 # define S 300000 # define inf 1e9 using namespace std; int read(){ int tmp=0,fh=1; char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();} while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();} return tmp*fh; } struct point{ int x,y; }q[N],now; struct kd_tree{ int pl,pr,tag; point p,l,r; }T[N]; priority_queue <double> hp; int st[N],top,rt,k,n,m,P; double ans[11]; bool cmpx(point x, point y){return x.x<y.x;} bool cmpy(point x, point y){return x.y<y.y;} double sqr(double x){return x*x;} void change(int p){ T[p].l.x=min(T[p].p.x,min(T[T[p].pl].l.x,T[T[p].pr].l.x)); T[p].r.x=max(T[p].p.x,max(T[T[p].pl].r.x,T[T[p].pr].r.x)); T[p].l.y=min(T[p].p.y,min(T[T[p].pl].l.y,T[T[p].pr].l.y)); T[p].r.y=max(T[p].p.y,max(T[T[p].pl].r.y,T[T[p].pr].r.y)); } int build(int l, int r, int tag){ if (l>r) return 0; int p=st[top--]; T[p].tag=tag; int mid=(l+r)/2; if (T[p].tag==0) nth_element(q+l,q+mid,q+r+1,cmpx); else nth_element(q+l,q+mid,q+r+1,cmpy); T[p].p=q[mid]; T[p].pl=build(l,mid-1,tag^1); T[p].pr=build(mid+1,r,tag^1); change(p); return p; } /*void recycle() void rebuild(int p){ len=0; recycle(p); build(1,len,tag); }*/ void extend(point now){ int p=st[top--]; T[p].p=now; if (rt==0){ rt=p; change(p); return; } int las,ths=rt; while (ths!=0){ las=ths; T[ths].l.x=min(T[ths].l.x,now.x); T[ths].l.y=min(T[ths].l.y,now.y); T[ths].r.x=max(T[ths].r.x,now.x); T[ths].r.y=max(T[ths].r.y,now.y); if (T[ths].tag==0&&now.x<=T[ths].p.x||T[ths].tag==1&&now.y<=T[ths].p.y) ths=T[ths].pl; else ths=T[ths].pr; } T[p].tag=T[las].tag^1; if (T[las].tag==0&&now.x<=T[las].p.x||T[las].tag==1&&now.y<=T[las].p.y) T[las].pl=p; else T[las].pr=p; change(p); } double dismn(int p){ double dis=0,disx=0,disy=0; if (now.x<T[p].l.x) disx=T[p].l.x-now.x; if (T[p].r.x<now.x) disx=now.x-T[p].r.x; if (now.y<T[p].l.y) disy=T[p].l.y-now.y; if (T[p].r.y<now.y) disy=now.y-T[p].r.y; if (k==1) return disx+disy; else return sqrt(sqr(disx)+sqr(disy)); } void query(int p){ double d0,d1,d2; if (p==0) return; if (k==1) d0=abs(T[p].p.x-now.x)+abs(T[p].p.y-now.y); else d0=sqrt(sqr(T[p].p.x-now.x)+sqr(T[p].p.y-now.y)); if (d0<hp.top()){ hp.pop(); hp.push(d0); } if (T[p].pl!=0) d1=dismn(T[p].pl); else d1=inf; if (T[p].pr!=0) d2=dismn(T[p].pr); else d2=inf; if (d1<d2){ if (d1<hp.top()) query(T[p].pl); if (d2<hp.top()) query(T[p].pr); } else { if (d2<hp.top()) query(T[p].pr); if (d1<hp.top()) query(T[p].pl); } } int main(){ n=read(), m=read(), k=read(), P=read(); char opt; for (int i=S; i>=1; i--) st[++top]=i; T[0].l.x=T[0].l.y=inf; T[0].r.x=T[0].r.y=-inf; for (int i=1; i<=n; i++) q[i].x=read(), q[i].y=read(); rt=build(1,n,0); for (int i=1; i<=m; i++){ scanf("\n%c",&opt); if (opt=='A'){ now.x=read(); now.y=read(); extend(now); // if ((ti++)%20000==0) rebuild(rt); } if (opt=='Q'){ now.x=read(); now.y=read(); while (hp.size()!=0) hp.pop(); for (int j=1; j<=P; j++) hp.push(inf); query(rt); for (int j=1; j<=P; j++){ ans[P-j+1]=hp.top(); hp.pop(); } for (int j=1; j<=P; j++) printf("%.4lf ",ans[j]); printf("\n"); } } }