CF835F Roads in the Kingdom

题目描述:

cf

luogu

题解:

基环树拆环$dp$。

先找环拆环,令$dp[i]$表示环上点$i$不经过环的最长链,$sum[i]$表示环上按某一确定顺序遍历顶点到第$i$个点的距离。

这两个是基环树拆环后都要处理的。

在树形$dp$先处理不经过环的最长链。

然后处理经过环的。

我们可以处理:

  1. $max_{l<r \leq i}{  l子树内最长链端点到r子树内最长链端点距离}$
  2. $max_{i \leq l<r}{  l子树内最长链端点到r子树内最长链端点距离}$
  3. $max_{r \leq i}{  r子树内最长链端点到第一个点子树内最长链端点距离}$
  4. $max_{i \leq l}{  l子树内最长链端点到最后一个点子树内最长链端点距离}$

对于断每一条边我们都能$O(1)$出直径。

最后两个$ans$取最大输出即可。

时间复杂度$O(n)$。

$set$也有$O(nlogn)$做法但是不如这个官方解法优秀。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 200050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,hed[N],cnt=1;
struct EG
{
    int to,nxt;
    ll w;
}e[2*N];
void ae(int f,int t,ll w)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    e[cnt].w = w;
    hed[f] = cnt;
}
int sta[2*N],tl,rt;
ll ste[2*N];
bool cir[N];
bool vis[N];
int dfs0(int u,int pre)
{
    if(vis[u])
    {
        rt = u;
        return 1;
    }
    vis[u] = 1;
    for(int now,j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(j==pre)continue;
        if((now=dfs0(to,j^1)))
        {
            if(now==1)
            {
                sta[++tl] = u;
                ste[tl] = e[j].w;
                cir[u] = 1;
                if(u!=rt)return 1;
            }
            return 2;
        }
    }
    return 0;
}
ll dp[N],sum[2*N],ans=0x3f3f3f3f3f3f3f3fll,ans0;
ll f[2][N],g[2][N];
ll dfs1(int u,int pre)
{
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(j==pre||cir[to])continue;
        ll tmp = dfs1(to,j^1)+e[j].w;
        ans0 = max(ans0,dp[u]+tmp);
        dp[u] = max(dp[u],tmp);
    }
    return dp[u];
}
int main()
{
//    freopen("tt.in","r",stdin);
    read(n);
    for(int u,v,w,i=1;i<=n;i++)
    {
        read(u),read(v),read(w);
        ae(u,v,w),ae(v,u,w);
    }
    dfs0(1,0);
    for(int i=1;i<=tl;i++)dfs1(sta[i],0);
    for(int i=1;i<=tl;i++)sum[i]=sum[i-1]+ste[i];
    ll mx = -ste[1];
    for(int i=1;i<=tl;i++)
    {
        f[0][i] = max(f[0][i-1],dp[sta[i]]+sum[i]+mx);
        mx = max(mx,dp[sta[i]]-sum[i]);
        f[1][i] = max(f[1][i-1],dp[sta[i]]+sum[i]-sum[1]);
    }
    mx = sum[tl];
    for(int i=tl;i>=1;i--)
    {
        g[0][i] = max(g[0][i+1],dp[sta[i]]-sum[i]+mx);
        mx = max(mx,dp[sta[i]]+sum[i]);
        g[1][i] = max(g[1][i+1],dp[sta[i]]-sum[i]+sum[tl]);
    }
    ans = f[0][tl];
    for(int i=1;i<=tl;i++)
        ans = min(ans,max(max(f[0][i],g[0][i+1]),f[1][i]+g[1][i+1]+ste[1]));
    printf("%lld\n",max(ans,ans0));
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/LiGuanlin1124/p/10785716.html