基环树小结

 持续更新ing

图中央的环显而易见,一般的初始化流程有两个

(1)找环

void Get_ring(LL u,LL fa){
    visit[u]=++cnt;
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(v==fa)
            continue;
        if(visit[v]){
            if(visit[v]<visit[u])
                continue;
            a[++num]=v;
            f[v]=true;
            for(;v!=u;v=pre[v]){
                a[++num]=pre[v];
                f[pre[v]]=true;
            }
        }else{
            pre[v]=u;
            Get_ring(v,u);
        }
    }
}

 (2)找边

void Get_edge(LL u,LL now){
    if(now==num+1)
        return;
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(v!=a[now+1])
            continue;
        eval[now]=dis[i].d;
        Get_edge(v,now+1);
    }
}

 

CF835F

  题目大意:删掉一条边,在保持联通性的基础上求最小直径

既然要保持连通性,就只能考虑在环上删边

先将环中的每个节点子树最大直径求出(不跨过环)

LL Get_d(LL u,LL fa){
    LL stmp=0;
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(v==fa||f[v])
            continue;
        stmp=MAX(stmp,Get_d(v,u));
        LL now=first[v]+dis[i].d;
        if(now>first[u]){
            second[u]=first[u];
            first[u]=now;
        }else if(now>second[u])
            second[u]=now;
    }
    stmp=MAX(stmp,first[u]+second[u]);
    return stmp;
}
for(LL i=1;i<=num;++i)
        mx[i]=Get_d(a[i],0);

 以上均为初始化,下面才是难点

   易证基环树的直径为 max{ 环上点子树直径与,跨环部分+左右端点直径和 }

    利用环的性质又可分为越过1-n与不越过1-n分别计算

 

    LL stmp=0;
    for(LL i=1;i<num;++i){
        s0[i]=MAX(s0[i-1],stmp+first[a[i]]);
        stmp+=eval[i];
    }
    stmp=0;
    for(LL i=num;i>1;--i){
        s1[i]=MAX(s1[i+1],stmp+first[a[i]]);
        stmp+=eval[i-1];
    }
    stmp=0;
    for(LL i=1;i<=num;++i){
        t0[i]=MAX(t0[i-1],MAX(mx[i],stmp+first[a[i]]));
        stmp=MAX(stmp,first[a[i]]);
        stmp+=eval[i];
    }
    stmp=0;
    for(LL i=num;i>=1;--i){
        t1[i]=MAX(t1[i+1],MAX(mx[i],stmp+first[a[i]]));
        stmp=MAX(stmp,first[a[i]]);
        stmp+=eval[i-1];
    }

My complete code:

#include<cstdio>
using namespace std;
typedef long long LL;
const LL maxn=400000;
struct node{
    LL to,next,d;
}dis[maxn*2];
LL n,num,cnt,ans; 
LL head[maxn],a[maxn],eval[maxn],visit[maxn],pre[maxn],s0[maxn],s1[maxn],t0[maxn],t1[maxn],mx[maxn],first[maxn],second[maxn];
bool f[maxn];

inline void add(LL u,LL v,LL d){
    dis[++num]=(node){v,head[u],d}; head[u]=num;
}
inline LL MAX(LL g1,LL g2){
    return g1>=g2?g1:g2;
}
inline LL MIN(LL g1,LL g2){
    return g1<=g2?g1:g2;
}
void Get_ring(LL u,LL fa){
    visit[u]=++cnt;
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(v==fa)
            continue;
        if(visit[v]){
            if(visit[v]<visit[u])
                continue;
            a[++num]=v;
            f[v]=true;
            for(;v!=u;v=pre[v]){
                a[++num]=pre[v];
                f[pre[v]]=true;
            }
        }else{
            pre[v]=u;
            Get_ring(v,u);
        }
    }
}
void Get_edge(LL u,LL now){
    if(now==num+1)
        return;
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(v!=a[now+1])
            continue;
        eval[now]=dis[i].d;
        Get_edge(v,now+1);
    }
}
LL Get_d(LL u,LL fa){
    LL stmp=0;
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(v==fa||f[v])
            continue;
        stmp=MAX(stmp,Get_d(v,u));
        LL now=first[v]+dis[i].d;
        if(now>first[u]){
            second[u]=first[u];
            first[u]=now;
        }else if(now>second[u])
            second[u]=now;
    }
    stmp=MAX(stmp,first[u]+second[u]);
    return stmp;
}
inline void init(){
    scanf("%lld",&n);
    for(LL i=1;i<=n;++i){
        LL u,v,d;
        scanf("%lld%lld%lld",&u,&v,&d);
        add(u,v,d);
        add(v,u,d);
    }
}
inline void solve(){
    num=0;
    Get_ring(1,0);
    a[num+1]=a[1];
    Get_edge(a[1],1);
    for(LL i=1;i<=num;++i)
        mx[i]=Get_d(a[i],0);
    LL stmp=0;
    for(LL i=1;i<num;++i){
        s0[i]=MAX(s0[i-1],stmp+first[a[i]]);
        stmp+=eval[i];
    }
    stmp=0;
    for(LL i=num;i>1;--i){
        s1[i]=MAX(s1[i+1],stmp+first[a[i]]);
        stmp+=eval[i-1];
    }
    stmp=0;
    for(LL i=1;i<=num;++i){
        t0[i]=MAX(t0[i-1],MAX(mx[i],stmp+first[a[i]]));
        stmp=MAX(stmp,first[a[i]]);
        stmp+=eval[i];
    }
    stmp=0;
    for(LL i=num;i>=1;--i){
        t1[i]=MAX(t1[i+1],MAX(mx[i],stmp+first[a[i]]));
        stmp=MAX(stmp,first[a[i]]);
        stmp+=eval[i-1];
    }

    ans=t0[num];
    for(LL i=1;i<num;++i)
        ans=MIN(ans,MAX(MAX(t0[i],t1[i+1]),s0[i]+s1[i+1]+eval[num]));
}
int main(){
    init();
    solve();
    printf("%lld",ans);
    return 0;
}

  

挖坑待填

posted @ 2018-11-16 20:46  y2823774827y  阅读(584)  评论(0编辑  收藏  举报