zoukankan      html  css  js  c++  java
  • bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan缩环&&环上单调队列

    1023: [SHOI2008]cactus仙人掌图

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 1141  Solved: 435
    [Submit][Status]

    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

    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 8
    10 1
    10 1 2 3 4 5 6 7 8 9 10

    Sample Output

    9

    HINT

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


     


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

      这种仙人掌一个点可能在多个环中,所以处理起来会比较麻烦,看了网上的最长的题解http://z55250825.blog.163.com/blog/static/150230809201412793151890/,和最短的标程http://hzwer.com/4645.html才有了基本的思路。很多的类似图论题都是在tarjan内部就完成大部分的操作,而我总是指望tarjan完成之后才统一处理,这样就丢掉了很多有用的信息。

      注意,bzoj上srand(time(0))是要RE的

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<set>
    using namespace std;
    #define PROB "cactus"
    #define MAXN 100010
    #define MAXV MAXN
    #define MAXE MAXV * 2
    #define INF 0x3f3f3f3f
    struct edge
    {
            int x,y,id;
    }e[MAXE];
    int n,m;
    int prv[MAXN];
    struct Edge
    {
            int sp,np,val,id;
            Edge *next;
    }E[MAXE],*V[MAXV];
    int tope;
    int dfn[MAXN],dfstime=0;
    int ans=0;
    void addedge(int x,int y,int id,int z=1)
    {
            E[++tope].np=y;
            E[tope].id=id;
            E[tope].sp=x;
            E[tope].val=z;
            E[tope].next=V[x];
            V[x]=&E[tope];
    }
    int len[MAXN];
    int arr[MAXN];
    int seq[MAXN];
    int vis[MAXN];
    void solve(int rt,int now)
    {
            int tota=0;
            int x,i;
            x=now;
            while (x!=rt)
            {
                    arr[tota++]=len[x];
                    x=prv[x];
            }
            arr[tota++]=0;
            for (i=0;i<tota;i++)
                    arr[i+tota]=arr[i];
            x=0;
            seq[0]=0;
            int tail=0,head=0;
            for (i=1;i<tota*2;i++)
            {
                    while (i-seq[head]>tota/2)head++;
                    ans=max(ans,arr[seq[head]]+(i-seq[head])+arr[i]);
                    while (tail>=head && arr[seq[tail]] + (i-seq[tail]) <=arr[i])tail--;
                    seq[++tail]=i;
            }
    }
    int low[MAXN];
    bool inc[MAXN];
    vector<int> ptr[MAXN];
    void dfs(int now,int pnt=-1)
    {
            low[now]=dfn[now]=++dfstime;
            Edge *ne;
            vis[now]=1;
            int x=-1,y=-1;
            int st=-1,rt;
            for (ne=V[now];ne;ne=ne->next)
            {
                    if (ne->np==prv[now])continue;
                    if (vis[ne->np]==1)
                    {
                            ptr[ne->np].push_back(now);
                            low[now]=min(low[now],dfn[ne->np]);
                    }else if (!vis[ne->np])
                    {
                            prv[ne->np]=now;
                            dfs(ne->np,now);
                            low[now]=min(low[now],low[ne->np]);
                    }
            }
            for (int i=0;i<ptr[now].size();i++)
            {
                    st=ptr[now][i],rt=now;
                    int sizc=1;
                    x=st;
                    inc[x]=true;
                    while (x!=rt)
                    {
                            x=prv[x];
                            inc[x]=true;
                            sizc++;
                    }
                    x=st;
                    int d=1;
                    int t=0;
                    while (x!=rt)
                    {
                            t=max(t,min(d,sizc-d)+len[x]);
                            d++;
                            x=prv[x];
                    }
                    ans=max(ans,t+len[rt]);
                    len[rt]=max(len[rt],t);
                    solve(rt,st);
            }
            x=y=0;
            if (!inc[now])
            {
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (dfn[ne->np]<dfn[now])continue;
                            if (y<len[ne->np]+1)
                            {
                                    y=len[ne->np]+1;
                                    if (x<y)swap(x,y);
                            }
                    }
            }
            if (low[now]==dfn[now])
            {
                    if (prv[now])ans=max(ans,len[now]+1+len[prv[now]]);
                    if (prv[now])len[prv[now]]=max(len[prv[now]],len[now]+1);
            }
            ans=max(ans,x+y);
            vis[now]=2;
    }
    int deg[MAXN];
    void work()
    {
            int i,x,y;
            for (i=0;i<m;i++)
            {
                    x=e[i].x;
                    y=e[i].y;
                    addedge(x,y,i);
                    addedge(y,x,i);
                    deg[x]++;
                    deg[y]++;
            }
            int core=0;
            for (i=1;i<=n;i++)
            {
                    if (deg[i]==1)core=i;
                    if (!core && deg[i]%2==1)core=i;
            }
            if (!core)core=1;
            dfs(core,core);
    }
    set<pair<int,int> > S;
    int main()
    {
            //freopen(PROB".in","r",stdin);
            //freopen(PROB".out","w",stdout);
            int l;
            scanf("%d%d",&n,&l);
            int i,j,k;
            int x,y,z;
            for (i=0;i<l;i++)
            {
                    scanf("%d",&x);
                    scanf("%d",&y);
                    for (j=1;j<x;j++)
                    {
                            scanf("%d",&z);
                            e[m].x=y;
                            e[m].y=z;
                            m++;
                            y=z;
                    }
            }
            for (i=0;i<m;i++)
            {
                    if (e[i].x>e[i].y)swap(e[i].x,e[i].y);
                    if (e[i].x==e[i].y || S.find(make_pair(e[i].x,e[i].y))!=S.end())
                    {
                            i--;m--;
                            continue;
                    }else
                    {
                            S.insert(make_pair(e[i].x,e[i].y));
                    }
                    e[i].id=i;
            }
            work();
            printf("%d
    ",ans);
    }
    by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

    本博客已停用,新博客地址:http://mhy12345.xyz

  • 相关阅读:
    servlet规范
    Java --Servlet 32个经典问题
    TCP的三次握手与四次挥手理解及面试题(很全面)
    TCP‘三次握手’和‘四次挥手’(通俗易懂)
    leetcode:122. Best Time to Buy and Sell Stock II(java)解答
    STM32通过调用库函数进行编程
    Swift下调用Touch ID实现指纹识别
    SpringMVC+MyBatis+JMS+JTA(分布式事务)
    windows下的两个等待函数
    Ubuntu 14.04正式公布,一个不眠之夜
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4125539.html
Copyright © 2011-2022 走看看