zoukankan      html  css  js  c++  java
  • 洛谷P4244 [SHOI2008]仙人掌图 II

    传送门

    首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径。

    那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并用环上一点的最长链加上它到环的根的距离来更新环的根的最长链。

    选择环上两点来更新直径,为了考虑到所有选择,将环断开并拷贝一份新的衔接在后面,形成长为二倍的串。用dp[i]+dp[j]+j-i(i、j为在串中位置)更新直径,单调队列维护单调递减的dp[i]-i,并且如果当前点和队头的距离超过半个环就队头出队。

    dfs的时候注意只用low[v]>dfn[u]的v来更新直径和u的最长链,判断是否有环的时候也注意让环的根成为环中深度最浅的,即判断dfn[v]>dfn[u],使u成为环的根,v为环的最后一个点。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=50010;
    int n,m,dp[N],ans,dis[N];
    int ver[20000010],Next[20000010],head[N],tot,f[N];
    void add(int x,int y){
        ver[++tot]=y;
        Next[tot]=head[x];
        head[x]=tot;
    }
    int tim,dfn[N],low[N],a[2*N],pos[2*N],q[2*N];
    void solve(int x,int y){
        int cnt=dis[y]-dis[x]+1;
        for(int i=y;i!=x;i=f[i]){
            a[cnt--]=i;
        }
        a[cnt]=x;
        cnt=dis[y]-dis[x]+1;
        for(int i=1;i<=cnt;i++){
            a[i+cnt]=a[i];
        }
        int l=1,r=1;
        pos[1]=1,q[1]=dp[a[1]]-1;
        for(int i=2;i<=2*cnt;i++){
            while(i-pos[l]>cnt/2&&l<=r)l++;
            ans=max(ans,q[l]+dp[a[i]]+i);
            while(l<=r&&q[r]<=dp[a[i]]-i)r--;
            q[++r]=dp[a[i]]-i;
            pos[r]=i;
        }
        for(int i=2;i<=cnt;i++){
            dp[x]=max(dp[x],dp[a[i]]+min(i-1,cnt-i+1));
        }
    }
    void dfs(int x,int fa){
        dfn[x]=low[x]=++tim;
        f[x]=fa;
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==fa)continue;
            if(!dfn[y]){
                dis[y]=dis[x]+1;
                dfs(y,x);
                low[x]=min(low[x],low[y]);
            }
            else low[x]=min(low[x],dfn[y]);
            if(dfn[x]<low[y]){
                ans=max(ans,dp[x]+dp[y]+1);
                dp[x]=max(dp[x],dp[y]+1);
            }
        }
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==fa)continue;
            if(f[y]!=x&&dfn[y]>dfn[x]){
                solve(x,y);
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,k,lst,x;i<=m;i++){
            scanf("%d",&k);
            lst=0;
            while(k--){
                scanf("%d",&x);
                if(lst){
                    add(lst,x),add(x,lst);
                }
                lst=x;
            }
        }
        dis[1]=1;
        dfs(1,0);
        printf("%d",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    一个业务场景的优化讨论
    关于Box Anemometer的安装配置遇到的几个坑
    CentOS6.5内 MySQL5.7.19编译安装
    CentOS6.5内 Oracle 11GR2静默安装
    始祖公——陈憺 河浦人文 (转载)
    Andriod- 从网络下载文件保存到SDCARD里
    Android Studio 如何添加第三方插件
    Android- SharedPreferences的封装
    Java/Andriod- 常用的 Android Studio 快捷键
    Java/Andriod- 动态权限申请
  • 原文地址:https://www.cnblogs.com/chloris/p/11853320.html
Copyright © 2011-2022 走看看