POJ 3567 Cactus Reloaded(仙人掌直径)

题意

裸的仙人掌直径。

题解

先考虑基环树的直径:先算出每颗“树”的直径,再在环上跑DP

再考虑仙人掌的直径:把每个基环树缩成一条边,边长为基环树深度。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 const int N=50010;
 8 const int M=10010;
 9 int cnt,head[N];
10 int c[N*2],dp[N],q[N*2],ans;
11 int dfn[N],low[N],tot,fa[N];
12 int n,m;
13 struct edge{
14     int to,nxt;
15 }e[M*20];
16 void add(int u,int v){
17     cnt++;
18     e[cnt].nxt=head[u];
19     e[cnt].to=v;
20     head[u]=cnt;
21 }
22 void getdp(int x,int y){
23     int l,r,i,m,p;
24     for(m=0;y!=x;y=fa[y])c[++m]=dp[y];
25     for(c[++m]=dp[x],i=1;i<m;i++)c[i+m]=c[i];
26     l=r=q[1]=1;p=m/2;
27     for(i=2;i<=m+p;i++){
28         while(l<=r&&i-q[l]>p)l++;
29         ans=max(ans,c[i]+c[q[l]]+i-q[l]);
30         while(l<=r&&c[i]>=c[q[r]]+i-q[r])r--;
31         q[++r]=i;
32     }
33     for(int i=1;i<m;i++)dp[x]=max(dp[x],c[i]+min(i,m-i));
34 }
35 void Tarjan(int u){
36     dfn[u]=low[u]=++tot;
37     for(int i=head[u];i;i=e[i].nxt){
38         int v=e[i].to;
39         if(fa[u]==v)continue;
40         if(dfn[v]==0){
41             fa[v]=u;
42             Tarjan(v);
43             low[u]=min(low[v],low[u]);
44             if(dfn[u]<low[v]){
45                 ans=max(ans,dp[v]+dp[u]+1);
46                 dp[u]=max(dp[u],dp[v]+1);
47             }
48         }else low[u]=min(low[u],dfn[v]);
49     }
50     for(int i=head[u];i;i=e[i].nxt){
51         int v=e[i].to;
52         if(fa[v]!=u&&dfn[u]<dfn[v])getdp(u,v);
53     }
54 }
55 int main(){
56     scanf("%d%d",&n,&m);
57     for(int i=1,a,x;i<=m;i++){
58         scanf("%d%d",&a,&x);
59         for(int j=1,y;j<a;j++){
60             scanf("%d",&y);
61             add(x,y);
62             add(y,x);
63             x=y;
64         }
65     }
66     Tarjan(1);
67     printf("%d",ans);
68     return 0;
69 }
View Code

 

posted @ 2018-07-28 10:33  Xu-daxia  阅读(364)  评论(0编辑  收藏  举报