• [BZOJ]1023: [SHOI2008]cactus仙人掌图


    Time Limit: 1 Sec  Memory Limit: 162 MB

    Description

      如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。

     

      举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6,5,4)、(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同时出现在前两个的简单回路里。另外,第三张图也不是仙人图,因为它并不是连通图。显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图上两点之间的距离为这两点之间最短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1,你的任务是求出给定的仙人图的直径。

    Input

      输入的第一行包括两个整数n和m(1≤n≤50000以及0≤m≤10000)。其中n代表顶点个数,我们约定图中的顶点将从1到n编号。接下来一共有m行。代表m条路径。每行的开始有一个整数k(2≤k≤1000),代表在这条路径上的顶点个数。接下来是k个1到n之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两个顶点的边。一条路径上可能通过一个顶点好几次,比如对于第一个样例,第一条路径从3经过8,又从8返回到了3,但是我们保证所有的边都会出现在某条路径上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。

    Output

      只需输出一个数,这个数表示仙人图的直径长度。

    Sample Input

     (样例1)

      15 3
      9 1 2 3 4 5 6 7 8 3
      7 2 9 10 11 12 13 10
      5 2 14 9 15 10
     (样例2)
      10 1
      10 1 2 3 4 5 6 7 8 9 10

    Sample Output

     (样例1)

      8
     (样例2)
      9

    HINT

      对第一个样例的说明:如图,6号点和12号点的最短路径长度为8,所以这张图的直径为8。

     

      【注意】使用Pascal语言的选手请注意:你的程序在处理大数据的时候可能会出现栈溢出。如果需要调整栈空间的大小,可以在程序的开头填加一句:{$M 5000000},其中5000000即指代栈空间的大小,请根据自己的程序选择适当的数值。

    Solution

      对仙人掌做一次dfs得到一棵dfs树,用f[i]表示i到子树中的点的最长距离,对于桥,我们直接更新f[i]=max(f[j]+1),并更新答案;对于环上的边,我们对每个环都统计一次答案并把信息汇总到环中深度最小的点上,汇总信息比较容易,考虑如何在环内统计答案,先把环拆成链,复制一份接在后面,然后对每个点i统计点i在环上向前的环大小一半的个数的点,即ans=max(f[i]+f[j]+dis(i,j))(dis(i,j)<=环的大小/2),这样就可以用单调队列可以维护,总复杂度O(n)。

    Code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 50000
    struct edge{int nx,t;}e[MN*4+5];
    int h[MN+5],en,d[MN+5],l[MN+5],cnt,fa[MN+5],f[MN+5],ans,a[MN*2+5],an,q[MN*2+5],ql,qr;
    inline void ins(int x,int y)
    {
        e[++en]=(edge){h[x],y};h[x]=en;
        e[++en]=(edge){h[y],x};h[y]=en;
    }
    void tj(int x)
    {
        int i,j;d[x]=l[x]=++cnt;
        for(i=h[x];i;i=e[i].nx)if(e[i].t!=fa[x])
        {
            if(!d[e[i].t])fa[e[i].t]=x,tj(e[i].t);
            l[x]=min(l[x],l[e[i].t]);
            if(l[e[i].t]>d[x])ans=max(ans,f[x]+f[e[i].t]+1),f[x]=max(f[x],f[e[i].t]+1);
        }
        for(i=h[x];i;i=e[i].nx)if(fa[e[i].t]!=x&&d[e[i].t]>d[x])
        {
            for(an=0,j=e[i].t;j!=x;j=fa[j])a[++an]=f[j];a[++an]=f[x];
            for(j=1;j<=an;++j)a[j+an]=a[j];
            for(j=ql=1,qr=0;j<=an<<1;++j)
            {
                while(ql<=qr&&j-q[ql]>an>>1)++ql;
                if(ql<=qr)ans=max(ans,a[j]+a[q[ql]]+j-q[ql]);
                while(ql<=qr&&a[j]-j>=a[q[qr]]-q[qr])--qr;
                q[++qr]=j;
            }
            for(j=1;j<an;++j)f[x]=max(f[x],a[j]+min(an-j,j));
        }
    }
    int main()
    {
        int n,m,k,x,y;
        n=read();m=read();
        while(m--)for(k=read(),x=read();--k;x=y)ins(x,y=read());
        tj(1);
        printf("%d",ans);
    }
  • 相关阅读:
    二进制位运算
    Leetcode 373. Find K Pairs with Smallest Sums
    priority_queue的用法
    Leetcode 110. Balanced Binary Tree
    Leetcode 104. Maximum Depth of Binary Tree
    Leetcode 111. Minimum Depth of Binary Tree
    Leetcode 64. Minimum Path Sum
    Leetcode 63. Unique Paths II
    经典的递归练习
    案例:java中的基本排序
  • 原文地址:https://www.cnblogs.com/ditoly/p/BZOJ1023.html
Copyright © 2020-2023  润新知