0、题意:给出一个N个结点的树,每条边有一个正整数权值,定义两个结点的距离为连接这两个结点路径上边权的和。对于每个结点i,它到其他N-1个结点都有一个距离,将这些距离从小到大排序,输出第K个距离。
1、分析:这个题我问了一下Claris,然后理解了,我们存下logn个分支结构,然后我们在分治结构中二分就好了QAQ
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 2000010
inline int read(){
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9'){
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
struct Edge{
int u, v, w, next;
} G[M];
int head[M], ed;
int size, f[M], son[M], ok[M];
int cnt, now;
int V[2][M], g[M], nxt[M], W[M], ED;
int rl[M], rr[M], el[M], er[M];
int q[M], tot, n, m;
inline void add(int u, int v, int w){
G[++ ed] = (Edge){u, v, w, head[u]};
head[u] = ed;
}
inline void ADD(int u, int v1, int v2, int w){
V[0][++ ED] = v1;
V[1][ED] = v2;
nxt[ED] = g[u];
g[u] = ED;
W[ED] = w;
}
inline void FindRoot(int x, int fa){
son[x] = 1; f[x] = 0;
for(int i = head[x]; i != -1; i = G[i].next) if(G[i].v != fa && !ok[i]){
FindRoot(G[i].v, x);
son[x] += son[G[i].v];
if(son[G[i].v] > f[x]) f[x] = son[G[i].v];
}
if(size - son[x] > f[x]) f[x] = size - son[x];
if(f[x] < f[now]) now = x;
}
inline void dfs(int x, int fa, int dis){
q[++ tot] = dis;
for(int i = head[x]; i != -1; i = G[i].next) if(G[i].v != fa && !ok[i]){
dfs(G[i].v, x, dis + G[i].w);
}
}
inline void dfs2(int x, int fa, int dis){
ADD(x, now, cnt, dis);
q[++ tot] = dis;
for(int i = head[x]; i != -1; i = G[i].next) if(G[i].v != fa && !ok[i]){
dfs2(G[i].v, x, dis + G[i].w);
}
}
inline void solve(int x){
q[rl[x] = ++ tot] = 0;
for(int i = head[x]; i != -1; i = G[i].next) if(!ok[i]){
dfs(G[i].v, x, G[i].w);
}
sort(q + rl[x], q + tot + 1);
rr[x] = tot;
for(int i = head[x]; i != -1; i = G[i].next) if(!ok[i]){
el[++ cnt] = tot + 1;
dfs2(G[i].v, x, G[i].w);
sort(q + el[cnt], q + tot + 1);
er[cnt] = tot;
}
for(int i = head[x]; i != -1; i = G[i].next) if(!ok[i]){
ok[i ^ 1] = 1;
f[0] = size = son[G[i].v];
FindRoot(G[i].v, now = 0);
solve(now);
}
}
inline int ask(int L, int r, int x){
int l = L, t = l - 1, mid;
while(l <= r){
mid = (l + r) / 2;
if(q[mid] <= x) l = (t = mid) + 1;
else r = mid - 1;
}
return t - L + 1;
}
inline int query(int x, int k){
int t = ask(rl[x], rr[x], k) - 1;
for(int i = g[x]; i != -1; i = nxt[i]) t += ask(rl[V[0][i]], rr[V[0][i]], k - W[i]) - ask(el[V[1][i]], er[V[1][i]], k - W[i]);
return t;
}
inline int getans(int x){
int l = 1, r = 10000 * (n - 1), mid;
while(l < r){
mid = (l + r) / 2;
if(query(x, mid) < m) l = mid + 1;
else r = mid;
}
return l;
}
int main(){
n = read(), m = read();
memset(head, -1, sizeof(head)); ED = ed = -1;
memset(g, -1, sizeof(g));
for(int i = 1; i < n; i ++){
int u = read(), v = read(), w = read();
add(u, v, w); add(v, u, w);
}
size = f[0] = n;
FindRoot(1, now = 0);
solve(now);
for(int i = 1; i <= n; i ++) printf("%d\n", getans(i));
return 0;
}