其他分享
首页 > 其他分享> > 基环树的直径

基环树的直径

作者:互联网

转载自LIOI_TEos的题解

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e6 + 100;
const ll mod = 20040820;
const int INF = 2147483647;
const int lim = 1e4 + 1;

int n, v[maxn], v2[maxn], r[maxn];
ll anss, st, ans2, ans3, cnt, dp[maxn<<1], s[maxn];//不知道题解上s数组为什么不开*2
ll ans, d[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    int next, to;
    ll w;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y, ll w)
{
    a[++len].to = y; a[len].next = head[x]; a[len].w = w;
    head[x] = len;
}

bool dfs(int now, int la)
{
    if(v[now] == 1)
    {
        v[now] = 2; r[++cnt] = now; v2[now] = 1;
        return 1;
    }
    v[now] = 1;
    for(int i=head[now]; i; i=a[i].next)
    {
        if(i!=((la-1)^1)+1 && dfs(a[i].to, i))
        {
            if(v[now]!=2)
            {
                r[++cnt] = now; v2[now] = 1; s[cnt] = s[cnt-1]+a[i].w;
            }
            else 
            {
                s[st-1] = s[st]-a[i].w;//s[0]
                //需要这样来得到一个正确的值是因为上一次倍长后没有清空
                return 0;
            }
            return 1;
        }
    }
    return 0;
}

void tree_dp(int now)
{
    v2[now] = 1;
    for(int i=head[now]; i; i=a[i].next)
    {
        int y = a[i].to;
        if(v2[y]) continue;
        tree_dp(y);
        ans = max(ans, d[now]+d[y]+a[i].w);//以now为轴连接两条链
        d[now] = max(d[now], d[y]+a[i].w);//now的对于它的下一个儿子的其它子节点连接的最长链
    }
}

ll brt(int root)
{
    st = cnt+1, ans2 = 0, ans3 = 0;
    dfs(root, 0);
    for(int i=st; i<=cnt; i++)
    {
        ans = 0;
        tree_dp(r[i]);//以环上的每个点为根求树的直径
        ans2 = max(ans2, ans);
        //长度是cnt-(st-1)
        dp[i+cnt-st+1] = dp[i] = d[r[i]];
        s[i+cnt-st+1] = s[i+cnt-st]+s[i]-s[i-1];//s[i-1]就是s[0]的用途?
    }
    deque<int> q;
    for(int i=st; i<=2*cnt-st+1; i++)//i的终点好奇怪?
    //哦,虽然很绕,但它是对的,cnt+cnt-(st-1)第一个cnt是倍长前的部分的终点,再加上一个长度
    {
        while(q.size() && q.front()<=i-cnt+st-1)
        {
            q.pop_front();
        }
        if(q.size())
        {
            ans3 = max(ans3, dp[i]+dp[q.front()]+s[i]-s[q.front()]);
        }
        while(q.size() && dp[q.back()]-s[q.back()]<=dp[i]-s[i])
        {
            q.pop_back();
        }
        q.push_back(i);
    }
    return max(ans2, ans3);
}

int main()
{
    n = read();
    for(int i=1; i<=n; i++)
    {
        int y = read(), z = read();
        add(i, y, z); add(y, i, z);
    }
    for(int i=1; i<=n; i++)
    {
        if(!v2[i])
        {
            anss += brt(i);
        }
    }
    printf("%lld\n", anss);
    
    return 0;
}

 

标签:ch,const,int,ll,long,基环树,maxn,直径
来源: https://www.cnblogs.com/Catherine2006/p/16548965.html