隐藏
「2014NOI模拟8」老逗找基友 - K-D树+树的直径 | Bill Yang's Blog
0%

「2014NOI模拟8」老逗找基友 - K-D树+树的直径

题目大意


题目分析

暴力模拟一下。
首先要将原图连好,要找到离自己最近的点。
K-D树即可。

接着考虑两个询问,对于第一个限制,显然尽量少的次数是固定的,即连通块数量,因此只需要考虑让所有连通块连起来后最大距离最小。
显然我们选择连接每个连通块的最长链的中点。

注:可以证明原图不存在环套树,全是树。


代码

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
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

inline int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(!isdigit(x)) {if(x=='-')bj=-1;x=getchar();}
while(isdigit(x)) {num=num*10+x-'0';x=getchar();}
return num*bj;
}

const int maxn=100005,K=2;

int D;

struct Point {
int d[K],Min[K],Max[K],id;
int ls,rs,val;
int& operator [] (int x) {return d[x];}
bool operator < (const Point& b) const {return d[D]<b.d[D];}
} p[maxn];

int ans,ansid;

struct KD_Tree {
#define lson p[index].ls
#define rson p[index].rs
void update(int index) {
for(int i=0; i<K; i++) {
p[index].Max[i]=p[index].Min[i]=p[index][i];
if(lson) {
p[index].Min[i]=min(p[index].Min[i],p[lson].Min[i]);
p[index].Max[i]=max(p[index].Max[i],p[lson].Max[i]);
}
if(rson) {
p[index].Min[i]=min(p[index].Min[i],p[rson].Min[i]);
p[index].Max[i]=max(p[index].Max[i],p[rson].Max[i]);
}
}
}
int build(int Left,int Right,int now) {
int mid=(Left+Right)>>1,root=mid;
D=now;
nth_element(p+Left,p+mid,p+Right+1);
if(Left<mid)p[root].ls=build(Left,mid-1,(now+1)%K);
if(Right>mid)p[root].rs=build(mid+1,Right,(now+1)%K);
update(root);
return root;
}
LL dist(Point a,Point b) {
LL ans=0;
for(int i=0; i<K; i++)ans+=abs(a[i]-b[i]);
return ans;
}
int get_min(int index,Point P) {
if(!index)return INT_MAX/2;
int ans=0;
for(int i=0; i<K; i++) {
if(p[index].Min[i]-P[i]>0)ans+=abs(p[index].Min[i]-P[i]);
if(P[i]-p[index].Max[i]>0)ans+=abs(P[i]-p[index].Max[i]);
}
return ans;
}
void find_min(int index,Point P,int now) {
if(!index)return;
if(p[index].id!=P.id) {
LL Dist=dist(p[index],P);
if(Dist<ans||(Dist==ans&&p[index].id<ansid))ans=Dist,ansid=p[index].id;
}
LL ldist=get_min(lson,P),rdist=get_min(rson,P);
if(ldist<=rdist) {
if(ldist<=ans)find_min(lson,P,(now+1)%K);
if(rdist<=ans&&P[now]+ans>=p[index][now])find_min(rson,P,(now+1)%K);
} else {
if(rdist<=ans)find_min(rson,P,(now+1)%K);
if(ldist<=ans&&P[now]-ans<=p[index][now])find_min(lson,P,(now+1)%K);
}
}
} kdtree;

int n,f[maxn],g[maxn],First=0,Second=0,Max=0,maxlen=0;
bool vst[maxn];
vector<int> edges[maxn];

void Dfs(int Now) {
vst[Now]=1;
for(int Next:edges[Now]) {
if(vst[Next])continue;
Dfs(Next);
if(f[Next]+1>f[Now]) {
g[Now]=f[Now];
f[Now]=f[Next]+1;
} else g[Now]=max(g[Now],f[Next]+1);
maxlen=max(maxlen,f[Now]+g[Now]);
}
}

int main() {
n=Get_Int();
for(int i=1; i<=n; i++) {
p[i][0]=Get_Int();
p[i][1]=Get_Int();
p[i].id=i;
}
int root=kdtree.build(1,n,0);
for(int i=1; i<=n; i++) {
ans=ansid=INT_MAX;
kdtree.find_min(root,p[i],0);
edges[p[i].id].push_back(ansid);
edges[ansid].push_back(p[i].id);
}
for(int i=1; i<=n; i++) {
if(vst[i])continue;
maxlen=0;
Dfs(i);
if((maxlen+1)/2>First) {
Second=First;
First=(maxlen+1)/2;
} else Second=max(Second,(maxlen+1)/2);
Max=max(Max,maxlen);
}
printf("%d\n",max(Max,First+Second+2));
return 0;
}
姥爷们赏瓶冰阔落吧~