zoukankan      html  css  js  c++  java
  • [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;
    }
    
    
  • 相关阅读:
    (转)导弹跟踪算法
    中文linux安装oracle界面乱码解决方案
    linux下创建oracle表空间
    [INS-20802] Oracle Net Configuration Assistant failed
    Centos6.5下Oracle 11g R2安装过程
    设置MYSQL数据库编码为UTF-8
    如何在linux系统中设置静态ip地址
    Oracle Net Configuration Assistant failed异常的解决方案
    解决安装oracle11g r2时提示pdksh conflicts with ksh-20100621-2.el6.i686问题
    CentOS增加swap分区大小
  • 原文地址:https://www.cnblogs.com/mollnn/p/13265158.html
Copyright © 2011-2022 走看看