版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/82564267
题意
求出树上所有点的最远距离。 。
题解
点分治。
树上最长路径,要么经过当前的重心,要么不经过。所以可以点分治来做。
首先求出重心每一个子树上节点到重心的距离,同时求出每一个子树中到重心的最远点。对于一个子树上的节点,如果他的最长路径经过当前重心,那么一定是他到重心的距离+其他子树中到根节点的最远点的最大值;如果不经过,递归到子树求解。而重心的最远点则是到所有子树中最远点的最大值。
问题变成如何对于一个序列,如何快速求出某个元素除自己外的最大值。维护最大值和次大值即可。
然后更新答案,递归子树。
代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 3e5+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
struct edge {
int to, nxt, w;
}e[nmax << 1];
int head[nmax], tot;
int ans[nmax], tmpdis[nmax];
void add_edge(int u, int v, int w) {
e[tot].to = v;
e[tot].w = w;
e[tot].nxt = head[u];
head[u] = tot++;
}
int t, n;
int sz[nmax], root, nowmn, totnode;
bool visit[nmax];
int nowmx, thenode, id, fm, sm, fmid, smid, seq[nmax];
void getroot(int u, int f) {
sz[u] = 1;
int mxpart = 0;
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(v != f && !visit[v]) {
getroot(v, u);
sz[u] += sz[v];
mxpart = max(mxpart, sz[v]);
}
}
mxpart = max(mxpart, totnode - sz[u]);
if(mxpart < nowmn) {
nowmn = mxpart;
root = u;
}
}
void getans(int u, int f, int dist) {
tmpdis[u] = dist;
if(dist > nowmx) {
nowmx = dist;
thenode = u;
}
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(!visit[v] && v != f) {
getans(v, u, dist + e[i].w);
}
}
}
void update(int u, int f, int base) {
ans[u] = max(ans[u], tmpdis[u] + base);
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(!visit[v] && v != f) {
update(v, u, base);
}
}
}
void solve(int u) {
visit[u] = true;
id = 1;
fm = fmid = sm = smid = 0;
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(!visit[v]) {
seq[v] = id;
nowmx = 0; thenode = 0;
getans(v, u, e[i].w);
if(fm == 0) {
fm = nowmx;
fmid = id;
} else if(nowmx > fm) {
sm = fm;
smid = fmid;
fm = nowmx;
fmid = id;
} else if(nowmx <= fm) {
if(nowmx > sm) {
sm = nowmx;
smid = id;
}
}
id++;
}
}
ans[u] = max(ans[u], fm);
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(!visit[v]) {
int tar = 0;
if(seq[v] == fmid) tar = sm;
else tar = fm;
update(v, u, tar);
}
}
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(!visit[v]) {
root = 0, nowmn = INF, totnode = sz[v];
getroot(v, u);
solve(root);
}
}
}
int main() {
// freopen("out.txt", "w", stdout);
scanf("%d", &t);
for(int kase = 1; kase <=t ; ++kase) {
scanf("%d", &n);
tot = 0;
for(int i = 0 ; i <= n; ++i) {
ans[i] = 0;
head[i] = -1;
visit[i] = false;
}
int u, v, w;
for(int i = 1; i < n; ++i) {
scanf("%d %d %d", &u, &v, &w);
u ++;
v ++;
add_edge(u, v, w);
add_edge(v, u, w);
}
root = 0, nowmn = INF, totnode = n;
getroot(1, -1);
solve(root);
printf("Case %d:\n", kase);
for(int i = 1; i <= n; ++i)
printf("%d\n", ans[i]);
}
return 0;
}