题目描述:给出一棵树,求出最小的 k k k,使得,且在树中存在路径 P P P,使得 k ≥ S k ≥ S k≥S 且 k ≤ E k ≤ E k≤E. ( k k k为路径 P P P上的边的权值和)
很显然的点分治的题目。
按照点分治的套路,
1.
1.
1.先对这棵树进行重心划分
2.
2.
2.统计过重心的点的路径
3.
3.
3.递归求解
在统计路径的时候,排序后枚举加
l
o
w
e
r
b
o
u
n
d
lowerbound
lowerbound,同时为避免统计到同一子树的(以当前划分的重心为根),可以每次统计一颗子树内的路径长度,就与已遍历子树进行答案统计,时间复杂度
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
具体见代码
C o d e Code Code
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5, inf = 1 << 30;
struct w{
int to, nx, s;
}head[MAXN + MAXN + 10];
int a[MAXN + 10], size[MAXN + 10], mx[MAXN + 10], dis[MAXN * 10 + 10], mn = inf;
int n, s, e, tot = 0;
bool vis[MAXN + 10];
inline int read();
inline void add(int, int, int, int);
void dfs(int, int, int);
int get_root(int, int, int);
void solve(int);
void calc(int);
int main(){
freopen ("B.in","r",stdin);
freopen ("B.out","w",stdout);
n = read(), s = read(), e = read();
for (register int i = 1; i < n; ++i){
int x = read(), y = read(), z = read();
add(x, y, i + i - 1, z);
add(y, x, i + i, z);
}
dfs(1, 0, 0);
solve(get_root(1, 0, n));
if (mn == inf) printf("-1\n");
else printf("%d\n", mn);
return 0;
}
inline int read(){
int x = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = (x << 1) + (x << 3) + (c & 15), c = getchar();
return x;
}
inline void add(int x, int y, int i, int z){head[i].to = y, head[i].nx = a[x], head[i].s = z, a[x] = i;}
void dfs(int x, int fa, int len){
size[x] = 1, dis[++tot] = len;
for (register int i = a[x]; i; i = head[i].nx){
int v = head[i].to;
if (v == fa || vis[v]) continue;
dfs(v, x, len + head[i].s);
size[x] += size[v];
}
}
int get_root(int x, int fa, int num){
int root = 0;
mx[x] = num - size[x];
for (register int i = a[x]; i; i = head[i].nx){
int v = head[i].to;
if (v == fa || vis[v]) continue;
int tmp = get_root(v, x, num);
if (!root || mx[tmp] < mx[root]) root = tmp;
mx[x] = max(mx[x], size[v]);
}
if (!root || mx[root] > mx[x]) root = x;
return root;
}
void solve(int x){
vis[x] = 1; tot = 0;
for (register int i = a[x]; i; i = head[i].nx){
int v = head[i].to, top = tot + 1;
if (vis[v]) continue;
dfs(v, x, head[i].s);
calc(top);
}
for (register int i = a[x]; i; i = head[i].nx){
int v = head[i].to;
if (vis[v]) continue;
solve(get_root(v, x, size[v]));
}
}
void calc(int top){
sort(dis + 1, dis + top);
for (register int i = top; i <= tot; ++i){
if (dis[i] >=s && dis[i] <= e) mn = min(mn, dis[i]);
int x = lower_bound(dis + 1, dis + top, s - dis[i]) - dis;
if (x < top && dis[x] + dis[i] >= s && dis[x] + dis[i] <= e) mn = min(mn, dis[x] + dis[i]);
}
}