zoukankan      html  css  js  c++  java
  • [bzoj1023][SHOI2008]cactus仙人掌图

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    给定一个仙人掌,求最大的两点最短距离。  n<=50000

    好难啊根本不会做。

    题解:先强行dfs把图拆成树,然后我们用f[i]表示i的子树中以i为起点的最长链长度。

    图中的每条边不是桥就是环上的边,对于一座桥,我们先更新一下答案,然后有f[i]=max(f[i],f[j]+1);

    对于一个环,我们只在深度最低的点处理,用环上所有点的f值更新它的f。然后我们考虑最优解在环上的情况,这时我们把环拆链,然后复制一条接起来,在这上面有ans=max(f[i]+f[j]+dis(i,j))。

    假设一条链标号1,2...tot...2tot,我们枚举i,这时候dis(i,j)=i-j,j比k优当且仅当f[i]+f[j]+i-j>f[i]+f[k]+i-k,也就是f[j]-j>f[k]-k,又因为我们在环上,所以长度不能超过tot/2,这个用一个单调队列维护就行了。

    顺便,判断桥的方法是low[j]>dfn[i],即j不能翻到i或之上的点,无向图判环要忽略到父亲的边。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MN 50000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int q[MN+5],dn=0,tot=0,a[2*MN+5],fa[MN+5],top,tail;
    int head[MN+5],n,cnt=0,m,k,f[MN+5],ans=0,dfn[MN+5],low[MN+5];
    struct edge{int to,next;}e[MN*10+5];
    
    void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    
    void dp(int rt,int last)
    {
        for(tot=0;last!=rt;last=fa[last]) a[++tot]=f[last];
        a[++tot]=f[rt];
        for(int i=1;i<=tot;i++)a[i+tot]=a[i];
        q[top=tail=1]=1;
        for(int i=2;i<=tot<<1;i++)
        {
            while(i-q[tail]>tot/2) tail++;
            ans=max(ans,a[i]+a[q[tail]]+i-q[tail]);
            while(top>=tail&&a[i]-i>=a[q[top]]-q[top]) --top;
            q[++top]=i;
        }
        for(int i=1;i<=tot;i++) f[rt]=max(f[rt],a[i]+min(tot-i,i));
    } 
    
    void tarjan(int x,int fat)
    {
        low[x]=dfn[x]=++dn;fa[x]=fat;
        for(int i=head[x];i;i=e[i].next)
        {
            if(!dfn[e[i].to]) tarjan(e[i].to,x),low[x]=min(low[x],low[e[i].to]);
            else if(e[i].to!=fat) low[x]=min(low[x],dfn[e[i].to]);
            if(e[i].to!=fat&&dfn[x]<low[e[i].to]) ans=max(ans,f[x]+f[e[i].to]+1),f[x]=max(f[x],f[e[i].to]+1);
        }
        for(int i=head[x];i;i=e[i].next)
            if(fa[e[i].to]!=x&&dfn[e[i].to]>dfn[x])
                dp(x,e[i].to);
    }
    
    int main()
    {
        n=read();k=read();
        for(int i=1;i<=k;i++)
        {
            int m=read(),pre=read();
            for(int j=2;j<=m;j++)
            {
                int x=read();
                ins(x,pre);pre=x;
            }
        }
        tarjan(1,0);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    2019 SDN上机第5次作业
    iOS 多线程
    安装pygame
    五分钟学会ios反编译
    反编译ipa包
    Flutter 混合开发(一)
    iOS开发-block异步实现return
    Mac下Anaconda的安装和使用
    挣值分析
    【PMP】挣值分析
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1023.html
Copyright © 2011-2022 走看看