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
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
Sample Output
8
解题思路
第一次接触仙人掌的蒟蒻QAQ
今天本来想学一下圆方树,然而还没学到怎么建就卡在了这道题上。
这是一道仙人掌入门题,思路也比较朴素。
对于一颗仙人掌,我们最不容易处理的就是环,对于一个环,我们视为一个点双连通分量。
所以我们使用tarjan
因为一个不在环内的点和环的顶点都可以直接更新答案。
答案用最长路径+子节点最长路径+1更新。
这个点的最长路径用子节点最长路径+1更新。
注意顺序!
在一个环的顶点将整个环抽出(因为是一个环,所以抽出后复制一遍成为一个两倍的链)
然后DP就可以啦
最长路径可以被中间链+子节点最长路径更新
这部分需要使用单调队列维护
最后更新顶点即可^_^
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 struct pnt{ 6 int hd; 7 int fa; 8 int dfn; 9 int low; 10 int mxc; 11 }p[1000000]; 12 struct ent{ 13 int twd; 14 int lst; 15 }e[1000000]; 16 int cnt; 17 int n,m,k; 18 int trc; 19 int ans; 20 int crt; 21 int crl[1000000]; 22 int q[1000000]; 23 int h,t; 24 void ade(int f,int t) 25 { 26 cnt++; 27 e[cnt].twd=t; 28 e[cnt].lst=p[f].hd; 29 p[f].hd=cnt; 30 } 31 void ringbrk(int st,int fi) 32 { 33 crt=0; 34 while(fi!=st) 35 { 36 crl[++crt]=p[fi].mxc; 37 fi=p[fi].fa; 38 } 39 crl[++crt]=p[st].mxc; 40 for(int i=1;i<crt;i++) 41 crl[crt+i]=crl[i]; 42 h=t=1; 43 q[1]=1; 44 int ln=crt/2; 45 for(int i=2;i<=crt+ln;i++) 46 { 47 while(h<=t&&i-q[h]>ln) 48 h++; 49 ans=max(ans,crl[q[h]]+crl[i]+i-q[h]); 50 while(h<=t&&crl[q[t]]+i-q[t]<=crl[i]) 51 t--; 52 q[++t]=i; 53 } 54 for(int i=1;i<crt;i++) 55 { 56 p[st].mxc=max(p[st].mxc,crl[i]+min(i,crt-i)); 57 } 58 } 59 void tarjan(int x) 60 { 61 p[x].dfn=p[x].low=++trc; 62 for(int i=p[x].hd;i;i=e[i].lst) 63 { 64 int to=e[i].twd; 65 if(to==p[x].fa)continue; 66 if(!p[to].dfn) 67 { 68 p[to].fa=x; 69 tarjan(to); 70 p[x].low=min(p[x].low,p[to].low); 71 if(p[x].dfn<p[to].low) 72 { 73 ans=max(ans,p[x].mxc+p[to].mxc+1); 74 p[x].mxc=max(p[x].mxc,p[to].mxc+1); 75 } 76 }else{ 77 p[x].low=min(p[x].low,p[to].low); 78 } 79 } 80 for(int i=p[x].hd;i;i=e[i].lst) 81 { 82 int to=e[i].twd; 83 if(p[to].fa!=x&&p[to].dfn>p[x].dfn) 84 { 85 ringbrk(x,to); 86 } 87 } 88 } 89 int main() 90 { 91 scanf("%d%d",&n,&m); 92 for(int i=1;i<=m;i++) 93 { 94 int frm,twd,nm; 95 scanf("%d%d",&nm,&frm); 96 for(int j=1;j<nm;j++) 97 { 98 scanf("%d",&twd); 99 ade(twd,frm); 100 ade(frm,twd); 101 frm=twd; 102 } 103 } 104 tarjan(1); 105 printf("%d\n",ans); 106 return 0; 107 }