zoukankan      html  css  js  c++  java
  • 基环树小结

     持续更新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;
    }
    

      

    挖坑待填

  • 相关阅读:
    ExtJS小技巧
    Oracle 表的行数、表占用空间大小,列的非空行数、列占用空间大小 查询
    NPM 私服
    IDEA 不编译java以外的文件
    SQL 引号中的问号在PrepareStatement 中不被看作是占位符
    Chrome 浏览器自动填表呈现淡黄色解决
    批量删除Maven 仓库未下载成功.lastupdate 的文件
    Oracle 11g 监听很慢,由于监听日志文件太大引起的问题(Windows 下)
    Hibernate 自动更新表出错 建表或添加列,提示标识符无效
    Hibernate 自动更新表出错 More than one table found in namespace
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/9971472.html
Copyright © 2011-2022 走看看