zoukankan      html  css  js  c++  java
  • BZOJ1023:[SHOI2008]cactus仙人掌图(圆方树,DP,单调队列)

    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

    8
    9

    HINT

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

     

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

    Solution

    如果只是求一颗树的直径的$DP$,应该是都会的,只需要记录一下$f[x]$表示从$x$点往下的最深深度就可以了。

    现在把问题搬到仙人掌上,说道仙人掌就想到圆方树。今年下半年……

    对于圆点,我们还是可以用$f$数组直接计算的。但是对于方点,相当于我们要求必须经过环的一颗基环树的直径。也就是求$f[i]+f[j]+dis(i,j)$的最大值,这个可以将环倍长用一个单调队列做。

    稍微具体一点就是用单调队列维护最大值,若当前位置($i$)和队首($j$)距离超过$frac{len}{2}$($len$为环长)时,就将队首弹出。因为会在后面的$i$(队首),$j+len$(当前位置)位置取到更优的值。

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<vector>
     5 #define N (200009)
     6 using namespace std;
     7 
     8 struct Edge{int to,next;}edge[N<<4];
     9 int n,m,bcc_num,ans,f[N],a[N],q[N];
    10 int DFN[N],Low[N],dfs_num,stack[N],top;
    11 int head[N],num_edge;
    12 vector<int>E[N];
    13 
    14 inline int read()
    15 {
    16     int x=0,w=1; char c=getchar();
    17     while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();}
    18     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
    19     return x*w;
    20 }
    21 
    22 void add(int u,int v)
    23 {
    24     edge[++num_edge].to=v;
    25     edge[num_edge].next=head[u];
    26     head[u]=num_edge;
    27 }
    28 
    29 void Tarjan(int x,int fa)
    30 {
    31     DFN[x]=Low[x]=++dfs_num; stack[++top]=x;
    32     for (int i=head[x]; i; i=edge[i].next)
    33         if (!DFN[edge[i].to])
    34         {
    35             Tarjan(edge[i].to,x);
    36             if (Low[edge[i].to]>DFN[x]) E[x].push_back(edge[i].to), top--;
    37             Low[x]=min(Low[x],Low[edge[i].to]);
    38             if (Low[edge[i].to]==DFN[x])
    39             {
    40                 E[x].push_back(++bcc_num);
    41                 while (top)
    42                 {
    43                     int now=stack[top--];
    44                     E[bcc_num].push_back(now);
    45                     if (now==edge[i].to) break;
    46                 }
    47             }
    48         }
    49         else if (edge[i].to!=fa)
    50             Low[x]=min(Low[x],DFN[edge[i].to]);
    51 }
    52 
    53 void DFS(int x,int fa)
    54 {
    55     for (int i=0; i<E[x].size(); ++i) DFS(E[x][i],x);
    56     if (x<=n)
    57     {
    58         int cmax=0;
    59         for (int i=0; i<E[x].size(); ++i)
    60         {
    61             cmax=max(cmax,f[E[x][i]]+1);
    62             if (cmax>f[x]) swap(f[x],cmax);
    63         }
    64         ans=max(ans,f[x]+cmax);
    65     }
    66     else
    67     {
    68         int l=1,r=0,cnt=0;
    69         for (int i=0; i<E[x].size(); ++i) a[++cnt]=E[x][i];
    70         for (int i=1; i<=cnt; ++i) a[cnt+i]=a[i];
    71         for (int i=1; i<=cnt*2; ++i)
    72         {
    73             while (l<=r && (i-q[l])>(cnt+1)/2) ++l;
    74             if (i>=cnt) ans=max(ans,f[a[i]]+f[a[q[l]]]+i-q[l]);
    75             while (l<=r && f[a[i]]-i>=f[a[q[r]]]-q[r]) r--;
    76             q[++r]=i;
    77         }
    78         for (int i=1; i<=cnt/2; ++i) f[x]=max(f[x],f[a[i]]+i-1);
    79         for (int i=cnt/2+1; i<=cnt; ++i) f[x]=max(f[x],f[a[i]]+cnt-i);
    80     }
    81 }
    82 
    83 int main()
    84 {
    85     n=bcc_num=read(); m=read();
    86     for (int i=1; i<=m; ++i)
    87     {
    88         int k=read(),last=0;
    89         for (int j=1; j<=k; ++j)
    90         {
    91             int x=read();
    92             if (last) add(last,x), add(x,last);
    93             last=x;
    94         }
    95     }
    96     Tarjan(1,0);
    97     DFS(1,0); printf("%d
    ",ans);
    98 }
  • 相关阅读:
    阿里云Ubuntu环境搭建Docker服务
    Cocos2d-x手机游戏开发中-组合动作
    Java中将时间戳转化为Date类型
    Ubuntu14.04+eclipse下cocos2d-x3.0正式版环境的搭建
    hdu 4901 The Romantic Hero(dp)
    scikit-learn:3.4. Model persistence
    桥接模式和NAT模式差别
    JavaScript入门:004—JS凝视的写法和基本运算符
    MySQL 创建用户 与 授权
    【观点见解】解读大数据的5个误区
  • 原文地址:https://www.cnblogs.com/refun/p/10459651.html
Copyright © 2011-2022 走看看