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 }