隐藏
「THUSC 2012」森林旅店 - K-D树+定期重构 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「THUSC 2012」森林旅店 - K-D树+定期重构

题目大意

    小H家旁边的树林可是一年四季度假的好地方。为了整合资源扩大效益,小H打算在树林中建立一些“泰山的小屋”,即在一些树木上建造一些小屋,让大家更加近距离地体会自然的美。
    不过有一个问题一直困扰着小H的计划,那就是森林中白蚁泛滥。大家都知道白蚁对于树木和木制品的危害,如果建造的房子周围白蚁成灾,那无疑就是将游客的人身安全置于一个危险的境地中了。因此小H在建造小屋的时候必须更加合理地考量房子的安全性。
    简而言之,我们可以认为森林里有许多的树木,其中有N个白蚁穴在这些树木上。在同一棵树上最多只有一个白蚁穴。
    小H想知道,如果他希望在某棵树上建立一座小屋,那么周围离它最近的P 个白蚁穴的距离分别是多少呢?
    同时由于随时可能发现新的白蚁穴,你的程序还应该支持动态地加入新发现的蚁穴。


题目分析

K-D树模板题。
有插入操作本来应该定期重构的,但是不知道为什么(数据水?)不重构就可以过,重构反而T。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<climits>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

typedef long long LL;

inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

const int maxn=200005,K=2;

int D,k;

struct Point {
double d[K],Min[K],Max[K];
int lson,rson;
Point() {lson=rson=0;}
double& operator [] (int x) {
return d[x];
}
bool operator < (const Point& b) const {
return d[D]<b.d[D];
}
};

struct KD_Tree {
Point p[maxn];
int size;
double dist(Point a,Point b) {
double ans=0;
for(int i=0; i<K; i++)ans+=pow(abs(a[i]-b[i]),k);
return ans;
}
#define pnow p[index]
#define ls p[index].lson
#define rs p[index].rson
void push_up(int index) {
for(int i=0; i<K; i++) {
pnow.Max[i]=pnow.Min[i]=pnow[i];
if(ls) {
pnow.Min[i]=min(pnow.Min[i],p[ls].Min[i]);
pnow.Max[i]=max(pnow.Max[i],p[ls].Max[i]);
}
if(rs) {
pnow.Min[i]=min(pnow.Min[i],p[rs].Min[i]);
pnow.Max[i]=max(pnow.Max[i],p[rs].Max[i]);
}
}
}
int build(int Left,int Right,int now) {
int mid=(Left+Right)>>1,index=mid;
D=now;
nth_element(p+Left,p+mid,p+Right+1);
ls=rs=0;
if(Left<mid)ls=build(Left,mid-1,(now+1)%K);
if(Right>mid)rs=build(mid+1,Right,(now+1)%K);
push_up(index);
return index;
}
int insert(int index,Point P,int now) {
if(!index) {
p[++size]=P;
push_up(size);
return size;
}
if(P[now]<=pnow[now])ls=insert(ls,P,(now+1)%K);
else rs=insert(rs,P,(now+1)%K);
push_up(index);
return index;
}
double get_min(int index,Point P) {
if(!index)return INT_MAX;
double ans=0;
for(int i=0; i<K; i++) {
if(pnow.Min[i]-P[i]>0)ans+=pow(abs(pnow.Min[i]-P[i]),k);
if(P[i]-pnow.Max[i]>0)ans+=pow(abs(P[i]-pnow.Max[i]),k);
}
return ans;
}
priority_queue<double> QMin;
void find_min(int index,Point P,int now) {
if(!index)return;
double Dist=dist(pnow,P);
if(Dist<QMin.top()) {
QMin.pop();
QMin.push(Dist);
}
double ldist=get_min(ls,P),rdist=get_min(rs,P);
if(ldist<rdist) {
if(ldist<=QMin.top())find_min(ls,P,(now+1)%K);
if(rdist<=QMin.top()&&P[now]+QMin.top()>=pnow[now])find_min(rs,P,(now+1)%K);
} else {
if(rdist<=QMin.top())find_min(rs,P,(now+1)%K);
if(ldist<=QMin.top()&&P[now]-QMin.top()<=pnow[now])find_min(ls,P,(now+1)%K);
}
}
} kdtree;

int n,q,t;

int main() {
n=Get_Int();
q=Get_Int();
k=Get_Int();
t=Get_Int();
int lim=sqrt(n);
for(int i=1; i<=n; i++) {
kdtree.size++;
kdtree.p[i][0]=Get_Int();
kdtree.p[i][1]=Get_Int();
}
int root=kdtree.build(1,n,0);
for(int i=1; i<=q; i++) {
char opt=' ';
while(!isalpha(opt))opt=getchar();
if(opt=='Q') {
Point p;
p[0]=Get_Int(),p[1]=Get_Int();
for(int j=1; j<=t; j++)kdtree.QMin.push(1e18);
kdtree.find_min(root,p,0);
vector<double> ans;
while(!kdtree.QMin.empty()) {
ans.push_back(kdtree.QMin.top());
kdtree.QMin.pop();
}
reverse(ans.begin(),ans.end());
for(auto x:ans)printf("%0.4lf ",pow(x,1.0/k));
putchar('\n');
} else {
Point p;
p[0]=Get_Int(),p[1]=Get_Int();
kdtree.insert(root,p,0);
}
// if(i%lim==0)root=kdtree.build(1,kdtree.size,0);
}
return 0;
}
姥爷们赏瓶冰阔落吧~