KD-Tree
啊哈~检验了一下自己KD-Tree的学习情况,还算可以,模板至少是记下来了。
支持插入(所以要带重建),查询最近的P个点的距离。
然而题目并没有说是按怎样的顺序输出这P个点?。。。(事实上是从近到远)
没啥好讲的……就是KD-Tree的裸操作……
1 //Tsinsen A1365 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<cstdlib> 8 #include<iostream> 9 #include<algorithm> 10 #define rep(i,n) for(int i=0;i<n;++i) 11 #define F(i,j,n) for(int i=j;i<=n;++i) 12 #define D(i,j,n) for(int i=j;i>=n;--i) 13 #define pb push_back 14 using namespace std; 15 inline int getint(){ 16 int v=0,sign=1; char ch=getchar(); 17 while(ch<‘0‘||ch>‘9‘){ if (ch==‘-‘) sign=-1; ch=getchar();} 18 while(ch>=‘0‘&&ch<=‘9‘){ v=v*10+ch-‘0‘; ch=getchar();} 19 return v*sign; 20 } 21 const int N=2e5+10; 22 typedef long long LL; 23 const LL INF=1e9; 24 /******************tamplate*********************/ 25 int n,m,K,P,D,p[N],cnt,tot,root; 26 struct node{ 27 int d[2],mn[2],mx[2],l,r,D,size; 28 int& operator [] (int x){return d[x];} 29 void read(){d[0]=getint();d[1]=getint();} 30 }t[N],tmp; 31 inline bool cmp(int x,int y){return t[x][D]<t[y][D];} 32 #define L t[o].l 33 #define R t[o].r 34 #define mid (l+r>>1) 35 void Push_up(int o){ 36 F(i,0,1){ 37 t[o].mn[i]=min(t[o][i],min(t[L].mn[i],t[R].mn[i])); 38 t[o].mx[i]=max(t[o][i],max(t[L].mx[i],t[R].mx[i])); 39 } 40 t[o].size=t[L].size+t[R].size+1; 41 } 42 int build(int l,int r,int dir){ 43 D=dir; 44 nth_element(p+l,p+mid,p+r+1,cmp); 45 int o=p[mid]; 46 t[o].D=dir; 47 L=l<mid?build(l,mid-1,dir^1):0; 48 R=r>mid?build(mid+1,r,dir^1):0; 49 Push_up(o); 50 return o; 51 } 52 void dfs(int o){ 53 if (!o) return; 54 dfs(L); 55 p[++cnt]=o; 56 dfs(R); 57 } 58 void rebuild(int &o){ 59 cnt=0; 60 dfs(o); 61 o=build(1,cnt,t[o].D); 62 } 63 void Insert(int &o,int dir){ 64 if (!o){ 65 o=++tot; t[o]=tmp; 66 F(i,0,1) t[o].mn[i]=t[o].mx[i]=t[o][i]; 67 t[o].D=dir; t[o].size=1; 68 }else{ 69 if (tmp[dir]<t[o][dir]){ 70 Insert(L,dir^1); Push_up(o); 71 if ((double)t[L].size>(double)t[o].size*0.7) rebuild(o); 72 }else{ 73 Insert(R,dir^1); Push_up(o); 74 if ((double)t[R].size>(double)t[o].size*0.7) rebuild(o); 75 } 76 } 77 } 78 inline LL get(LL v){ 79 if (K==1) return abs(v); 80 else return v*v; 81 } 82 inline double ANS(LL v){ 83 if (K==1) return v; 84 else return sqrt(double(v)); 85 } 86 inline LL getdis(int o){ 87 if (!o) return 1e16; 88 LL ans=0; 89 F(i,0,1){ 90 if (t[o].mn[i]>tmp[i]) ans+=get(t[o].mn[i]-tmp[i]); 91 if (t[o].mx[i]<tmp[i]) ans+=get(tmp[i]-t[o].mx[i]); 92 } 93 return ans; 94 } 95 inline LL dis(int o){return get(t[o][0]-tmp[0])+get(t[o][1]-tmp[1]);} 96 priority_queue<LL>Q; 97 void query(int o){ 98 if (!o) return; 99 LL dl=getdis(L),dr=getdis(R),d0=dis(o); 100 if (d0<Q.top()){Q.pop(); Q.push(d0);} 101 if (dl<dr){ 102 if (dl<Q.top()) query(L); 103 if (dr<Q.top()) query(R); 104 }else{ 105 if (dr<Q.top()) query(R); 106 if (dl<Q.top()) query(L); 107 } 108 } 109 double ans[5]; 110 int main(){ 111 #ifndef ONLINE_JUDGE 112 freopen("A1365.in","r",stdin); 113 freopen("A1365.out","w",stdout); 114 #endif 115 F(i,0,1) t[0].mn[i]=INF,t[0].mx[i]=-INF; 116 t[0].size=0; 117 tot=n=getint(); m=getint(); K=getint(); P=getint(); 118 F(i,1,n) {t[i].read(); p[i]=i;} 119 root=build(1,n,1); 120 char cmd[5]; 121 F(i,1,m){ 122 scanf("%s",cmd); 123 tmp.read(); 124 if (cmd[0]==‘Q‘){ 125 F(j,1,P) Q.push(1e16); 126 query(root); 127 D(j,P,1){ 128 ans[j]=ANS(Q.top()); 129 Q.pop(); 130 } 131 F(j,1,P) 132 printf("%.4f%c",ans[j],j==P ? ‘\n‘ : ‘ ‘); 133 }else{ 134 Insert(root,1); 135 } 136 } 137 return 0; 138 }
A1365. 森林旅店
时间限制:1.0s 内存限制:256.0MB
总提交次数:817 AC次数:58 平均分:37.59
将本题分享到:
试题来源
清华大学2012年信息学优秀高中学子夏令营
问题描述
小H家旁边的树林可是一年四季度假的好地方。为了整合资源扩大效益,小H打算在树林中建立一些“泰山的小屋”,即在一些树木上建造一些小屋,让大家更加近距离地体会自然的美。
不过有一个问题一直困扰着小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)建造一个小屋,请告知周边的蚁穴情况。
输出格式
对于每组询问,输出P 个实数,以单个空格隔开,表示距离最近的 个蚁穴的距离,精确到小数点后4位。
样例输入
1 3 1 1
0 0
Q 0 2
A 0 3
Q 0 2
样例输出
2.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次。