仙人掌DP,f[i]表示i的子仙人掌里以i为一个端点走最短路的最长链
dfs一颗仙人掌,带上tarjan的low和dfn,对于一个点,如果是这个环的根,用这个环上的所有点转移,如果不是这个环的根,不用这个环上的点转移。
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<ctime> #include<cmath> #include<algorithm> #include<iomanip> #include<queue> #include<map> #include<bitset> #include<stack> #include<vector> #include<set> using namespace std; #define MAXN 100010 #define MAXM 10000010 #define INF 1000000000 #define MOD 1000000007 #define ll long long struct vec{ int to; int fro; }; vec mp[MAXM]; int tai[MAXN],cnt; int fa[MAXN],f[MAXN]; int dfn[MAXN],low[MAXN],tim; int dep[MAXN]; int a[MAXN]; int q[MAXN],hd,tl; int n,M,m; int ans; inline void be(int x,int y){ mp[++cnt].to=y; mp[cnt].fro=tai[x]; tai[x]=cnt; } inline void bde(int x,int y){ be(x,y); be(y,x); } void dp(int rt,int ed){ int i; int N=dep[ed]-dep[rt]+1; for(i=ed;i!=fa[rt];i=fa[i]){ a[N--]=f[i]; } N=dep[ed]-dep[rt]+1; for(i=N+1;i<=N+N;i++){ a[i]=a[i-N]; } hd=1,tl=0; q[++tl]=1; for(i=2;i<=N+N/2;i++){ while(hd<=tl&&i-q[hd]>N/2){ hd++; } ans=max(ans,a[i]+a[q[hd]]+i-q[hd]); while(hd<=tl&&a[i]-i>=a[q[tl]]-q[tl]){ tl--; } q[++tl]=i; } for(i=2;i<=N;i++){ f[rt]=max(f[rt],a[i]+min(i-1,N-i+1)); } } void dfs(int x){ int i,y; dfn[x]=low[x]=++tim; dep[x]=dep[fa[x]]+1; for(i=tai[x];i;i=mp[i].fro){ y=mp[i].to; if(y==fa[x]){ continue ; } if(!dfn[y]){ fa[y]=x; dfs(y); } low[x]=min(low[x],low[y]); if(low[y]>dfn[x]){ ans=max(ans,f[x]+f[y]+1); f[x]=max(f[x],f[y]+1); } } for(i=tai[x];i;i=mp[i].fro){ y=mp[i].to; if(fa[y]!=x&&dfn[y]>dfn[x]){ dp(x,y); } } } int main(){ int i,x,y; scanf("%d%d",&n,&M); while(M--){ scanf("%d",&m); scanf("%d",&x); for(i=2;i<=m;i++){ scanf("%d",&y); bde(x,y); x=y; } } dfs(1); printf("%d\n",ans); return 0; } /* */