• [IOI2008] Island


    Description

    给出一个基环树森林,让你求出所有基环树的直径之和。

    Solution

    基环树的直径,要么是某个子树的直径,要么是两个子树的直径加上一段环上路径

    考虑后者,设 (f_p) 表示从 (p) 开始到 (p) 的子树中结点的最长路径

    对于环上序号为 (i,j) 的两个点,它们之间可以选择的有两条不同的路径,其贡献分别为

    [f_i+f_j+sum_j-sum_i, f_i+f_j+len-sum_j+sum_i ]

    其中 (len) 是环的总长,(sum) 是环上长度前缀和

    观察到在以上两式中,有效的部分实际上是以 (f+sum)(f-sum) 整体出现的,因此我们扫描 (j) 并记录所有 (i<j) 中最大的 (f_i - sum_i)(f_i + sum_i) 即可

    找环的时候如果需要错位可以借用 std::rotate

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1e6+5;
    
    int n,m,t1,t2,t3;
    int used[N],vis[N];
    vector <pair<signed,signed> > g[N];
    vector <pair<signed,signed> > sta;
    int cir[N],sum[N],tot,f[N],res;
    
    void dfs(signed p,signed fa,signed fadis)
    {
        vis[p]=1;
        sta.push_back({p,fadis});
        for(pair<signed,signed> pr:g[p])
        {
            if(tot) break;
            int q=pr.first, w=pr.second;
            if(q==fa)
            {
                fa=-fa;
                continue;
            }
            if(vis[q])
            {
                tot=1;
                cir[tot]=q;
                sum[tot]=w;
                while(sta.size() && sta.back().first!=q)
                {
                    ++tot;
                    cir[tot]=sta.back().first;
                    sum[tot]=sta.back().second;
                    sta.pop_back();
                }
            }
            else
            {
                dfs(q,p,w);
            }
        }
        if(tot==0) sta.pop_back();
    }
    
    void dp(int p)
    {
        used[p]=1;
        for(pair<signed,signed> pr:g[p])
        {
            int q=pr.first, w=pr.second;
            if(used[q]==0)
            {
                dp(q);
                res=max(res,f[p]+f[q]+w);
                f[p]=max(f[p],f[q]+w);
            }
        }
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>t2>>t3;
            t1=i;
            g[t1].push_back({t2,t3});
            g[t2].push_back({t1,t3});
        }
    
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(used[i]==0)
            {
                int m1=-1e18, m2=-1e18;
                res=0, tot=0;
                dfs(i,0,0);
    
                rotate(sum+1,sum+tot,sum+tot+1);
    
                for(int i=1;i<=tot;i++)
                {
                    used[cir[i]]=1;
                    sum[i]+=sum[i-1];
                }
                for(int i=1;i<=tot;i++)
                {
                    dp(cir[i]);
                }
                for(int i=1;i<=tot;i++)
                {
                    res=max(res, max(sum[i]+f[cir[i]]+m1, sum[tot]-sum[i]+f[cir[i]]+m2));
                    m1=max(m1, f[cir[i]]-sum[i]);
                    m2=max(m2, f[cir[i]]+sum[i]);
                }
                ans+=res;
            }
        }
        cout<<ans;
    }
    
    
  • 相关阅读:
    Activity之间的数据传递
    解析JSON
    使用HTTP协议访问网路
    WebView的初体验
    Alarm机制用于定时服务
    IntentService和Service执行子线程对比
    前台服务
    Android四大组件之服务
    异步消息处理机制,UI更新
    Git学习
  • 原文地址:https://www.cnblogs.com/mollnn/p/13265158.html
Copyright © 2020-2023  润新知