bzoj3124
树形dp
先拎出来一条直径,然后看直径上挂着的每条链,如果等于左边就把左端点放过来,等于右端点就把右端点放过来
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 2e5 + 5; struct edge { int nxt, to, w; } e[N << 1]; int n, cnt = 1, ans; ll dis[N]; int head[N], q[N], pre[N], mark[N]; int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } void link(int u, int v, int w) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].to = v; e[cnt].w = w; } int bfs(int s) { int ret = s; memset(dis, -1, sizeof(dis)); dis[s] = 0; int l = 1, r = 0; q[++r] = s; while(l <= r) { int u = q[l++]; for(int i = head[u]; i; i = e[i].nxt) if(dis[e[i].to] == -1) { dis[e[i].to] = dis[u] + e[i].w; q[++r] = e[i].to; pre[e[i].to] = u; if(dis[e[i].to] > dis[ret]) ret = e[i].to; } } return ret; } ll dfs(int u, int last) { ll ret = 0; for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last && !mark[e[i].to]) ret = max(ret, dfs(e[i].to, u) + e[i].w); return ret; } int main() { n = read(); for(int i = 1; i < n; ++i) { int u = read(), v = read(), w = read(); link(u, v, w); link(v, u, w); } int s = bfs(1), t = bfs(s); printf("%lld\n", dis[t]); for(int i = t; i != s; i = pre[i]) mark[i] = 1; mark[s] = 1; int left = s, right = t, flag = 1; for(int i = t; i != s; i = pre[i]) { ll d = dfs(i, 0); if(d == dis[i]) { left = i; flag = 0; } if(d == dis[t] - dis[i]) right = i; } for(int i = right; i != left; i = pre[i]) ++ans; printf("%d\n", ans); return 0; }