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
", 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
", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/19992147orz/p/7791776.html