bzoj1023 [SHOI2008]cactus仙人掌图

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即指代栈空间的大小,请根据自己的程序选择适当的数值。

 

正解:仙人掌+$tarjan$+单调队列。

这题是仙人掌入门题,然而我看了好久的题解才看懂。。

首先要明确一点,树的直径算法,也就是两遍$bfs$的做法是错的,这个在$2015$年集训队论文集中$wys$的论文里有指出。

然后这是棵仙人掌,我们考虑一下如何求解。

首先我们还是和树形$dp$的做法一样。先遍历一遍整棵仙人掌,搞清楚仙人掌的结构是怎样的。

当我们遍历的结点不在环内时,直接按照树形$dp$的做法,用最长链和次长链更新$ans$就行了。

当我们遍历的结点在环内时,我们直接把环抠出来,另外处理。

然后我们可以把环拉成一条链,也就是把环倍长。

我们用这个环更新答案时,要考虑一种情况,就是环上两个点的最短距离和两个点子树内的最长链,也就是$f[i]$相加。

这个情况很不好处理,但是我们可以发现,把环拉成序列以后,我们要求的就是在序列中距离在序列长度的$\frac{1}{4}$以内(因为环已经倍长辣)的最优解。

我们把环拉成序列以后,因为扫描序列是顺时针操作的,所以序列中相邻的点在环中也是相邻的,所以两点之间的距离就是它们在序列中的下标差。

于是我们的$ans$就是$max(f[u]+f[v]+u-v)$($idu>idv$且$idu-idv<\frac{1}{4}len$,$len$为序列长度)。于是我们发现这个东西可以用单调队列做。

我们更新完答案以后,再顺便更新一下环顶的$f$值,因为其他的$f$值以后都不会再用到了,我们只要更新环顶的$f$就能做到不影响答案了。

于是这道题就被我们完美地解决了。

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <complex>
 5 #include <cstring>
 6 #include <cstdlib>
 7 #include <cstdio>
 8 #include <vector>
 9 #include <cmath>
10 #include <queue>
11 #include <stack>
12 #include <map>
13 #include <set>
14 #define inf (1<<30)
15 #define N (200010)
16 #define il inline
17 #define RG register
18 #define ll long long
19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
20 
21 using namespace std;
22 
23 struct edge{ int nt,to; }g[1000010];
24 
25 int head[N],fa[N],dep[N],dfn[N],low[N],f[N],a[N],q[N],n,m,num,cnt,ans;
26 
27 il int gi(){
28     RG int x=0,q=1; RG char ch=getchar();
29     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
30     if (ch=='-') q=-1,ch=getchar();
31     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
32     return q*x;
33 }
34 
35 il void insert(RG int from,RG int to){
36     g[++num]=(edge){head[from],to},head[from]=num; return;
37 }
38 
39 il void circle(RG int rt,RG int x){ //环上dp
40     RG int top=dep[x]-dep[rt]+1; a[1]=f[rt];
41     for (RG int i=x;i!=rt;i=fa[i]) a[top--]=f[i];
42     RG int h=1,t=1; top=dep[x]-dep[rt]+1,q[1]=1;
43     for (RG int i=1;i<=top;++i) a[i+top]=a[i]; //环倍长
44     for (RG int i=2;i<=(top<<1);++i){
45     while (h<t && i-q[h]>(top>>1)) h++;
46     ans=max(ans,a[i]+a[q[h]]+i-q[h]);
47     while (h<=t && a[q[t]]-q[t]<=a[i]-i) t--;
48     q[++t]=i;
49     }
50     for (RG int i=2;i<=top;++i) //更新环顶结点的f值
51     f[rt]=max(f[rt],a[i]+min(i-1,top-i+1));
52     return;
53 }
54 
55 il void dfs(RG int x,RG int p){
56     fa[x]=p,dep[x]=dep[p]+1;
57     dfn[x]=low[x]=++cnt; RG int v;
58     for (RG int i=head[x];i;i=g[i].nt){
59     v=g[i].to; if (v==p) continue;
60     if (!dfn[v]) dfs(v,x),low[x]=min(low[x],low[v]);
61     else low[x]=min(low[x],dfn[v]);
62     if (dfn[x]<low[v]){ //没有形成环的情况
63         ans=max(ans,f[x]+f[v]+1);
64         f[x]=max(f[x],f[v]+1);
65     }
66     }
67     for (RG int i=head[x];i;i=g[i].nt){ //判断是否有环
68     v=g[i].to; if (v==p) continue;
69     if (fa[v]!=x && dfn[x]<dfn[v]) circle(x,v);
70     }
71     return;
72 }
73 
74 il void work(){
75     n=gi(),m=gi();
76     for (RG int i=1,k,x,v;i<=m;++i){
77     k=gi(),x=gi();
78     for (RG int j=1;j<k;++j)
79         v=gi(),insert(x,v),insert(v,x),x=v;
80     }
81     dfs(1,0); printf("%d\n",ans); return;
82 }
83 
84 int main(){
85     File("cactus");
86     work();
87     return 0;
88 }

 

posted @ 2017-03-29 18:21  wfj_2048  阅读(254)  评论(0编辑  收藏  举报