ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF835F Roads in the Kingdom

2021-07-18 14:33:24  阅读:204  来源: 互联网

标签:Kingdom 环上 int dis CF835F Roads 直径 include 前缀


Description

给定一棵基环树,现在可以删去环上的一条边,最小化删变后树的直径。求直径大小。

Solution

把环上的边删完后,就得到一个森林。删去环上的边对森林里树的直径是无影响的,这是直径的第一种情况。

第二种情况就是两段非环路径加上一段环上路径,记 \(c_i\) 表示 \(i\) 到子树内的最长链,最大直径就可以表示为 \(c_i+c_j+dis_{i,j}\)。删去一条环上的边,断成链。假设删的是 \([i-1,i]\) 这条边,记 \(s_i\) 表示边权的前缀和 (\(a_0=a_m\)),有三种情况 \((u<v)\):

  1. \(u,v\in[1,i-1]\),就用 \(c_v+c_u+s_v-s_u\) 更新答案,只需要维护 \(c_u-s_u\) 的前缀最大,然后再对 \(v\) 做前缀。
  2. \(u,v\in[i,m]\),和 1 类似,答案一样,维护 \(c_v+s_v\) 后缀最大,再对 \(u\) 做后缀。
  3. \(u\in[i,m],v\in[1,i-1]\) ,答案是 \(s_u+c_u+c_v+s_m-s_v\),分别维护前缀后缀最大。
#include<stdio.h>
#include<map>
#include<algorithm>
using namespace std;

typedef long long ll;

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
    return flag? x:-x; 
}

const int N=2e5+7;

map<int,int> mp[N];

struct E{
    int next,to,dis;
}e[N<<1];

int head[N],cnt=0,fa[N];

inline void add(int id,int to,int d){
    e[++cnt]=(E){head[id],to,d};
    head[id]=cnt;
}

bool ins[N],imp[N];
int sta[N],top=0,a[N],m=0;

void dfs(int u){
    static bool tag=0;
    sta[++top]=u;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u]) continue;
        if(ins[v]){
            tag=1; int y;
            do{
                imp[y=sta[top--]]=1;
                a[++m]=y;
            }while(y!=v);
            return ;
        }
        ins[u]=1,fa[v]=u,dfs(v),ins[u]=0;
        if(tag) return ;
    }
    top--;
}

int rt;
ll c[N],mx=0;
ll dfs1(int u,ll ret,int fa){
    if(ret>mx) mx=ret,rt=u;
    for(int i=head[u];i;i=e[i].next)
        if(e[i].to!=fa&&!imp[e[i].to]) dfs1(e[i].to,e[i].dis+ret,u);
}

ll G,F[2][N],s[N],H[2][N];

int main(){
    freopen("roads.in","r",stdin);
    freopen("roads.out","w",stdout);
    int n=read();
    for(int i=1;i<=n;i++){
        int u=read(),v=read(),d=read();
        mp[u][v]=mp[v][u]=d;
        add(u,v,d),add(v,u,d);
    }
    dfs(1); ll ans=1ll<<60,ans1=0;
    for(int i=1;i<=n;i++) fa[i]=0; a[0]=a[m];
    for(int i=1;i<=m;i++){
        imp[a[i]]=0;
         mx=rt=0,dfs1(a[i],0,0),c[i]=mx;
        mx=0,dfs1(rt,0,0),ans1=max(ans1,mx);
        s[i]=s[i-1]+mp[a[i-1]][a[i]];
        imp[a[i]]=1;
    }    
    G=F[0][0]=F[1][0]=-(1ll<<60);
    for(int i=1;i<=m;i++){
        F[0][i]=max(F[0][i-1],G+s[i]+c[i]);
        F[1][i]=max(F[1][i-1],s[i]+c[i]);
        G=max(G,c[i]-s[i]);
    }
    G=H[0][m+1]=H[1][m+1]=-(1ll<<60);
    for(int i=m;i;i--){
        H[0][i]=max(H[0][i+1],G-s[i]+c[i]);
        H[1][i]=max(H[1][i+1],c[i]-s[i]+s[m]);
        G=max(G,c[i]+s[i]);
    }
    for(int i=1;i<=m;i++)
        ans=min(ans,max(max(F[0][i-1],H[0][i]),F[1][i-1]+H[1][i]));
    printf("%lld",max(ans,ans1));
}

标签:Kingdom,环上,int,dis,CF835F,Roads,直径,include,前缀
来源: https://www.cnblogs.com/wwlwQWQ/p/15026481.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有