题意是仙人掌图直径。
大概做法就是树的直径dp求法加上基环树的技巧特技。
改了好长好长时间啊。
参考题解: http://z55250825.blog.163.com/blog/static/150230809201412793151890/
很细致。。

code:


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int H[50005],X[20000005],P[20000005],tot=1;
int dp[50005];
inline void add(int x,int y){
	P[++tot]=y;X[tot]=H[x];H[x]=tot;
}
int stk[50005],top;
int dfn[50005];
int low[50005],tim;
int ans;
int list[100005],t;
struct N{
	int pos,w;
	N(int a=0,int b=0){
		pos=a;w=b;
	}
};
struct dddl{
	N q[100005];
	int h,t;
	void clear(){
		h=t=0;
	}
	void pop(int x){
		if(q[h].pos==x) h++;
	}
	int ask(){
		return q[h].w;
	}
	void push(N a){
		while(h<t&&q[t-1].w<=a.w) t--;
		q[t++]=a;
	}
}q;
bool debug;
int fa[50005];
void dfs(int x){
	dfn[x]=low[x]=++tim;
	for(int i=H[x];i;i=X[i]){
		if(P[i]==fa[x])continue;
		if(fa[P[i]]&&dfn[P[i]]>dfn[x]){
			//find circle
			int k=P[i];
			t=0;
			while(k!=x) list[t++]=k,k=fa[k];
			list[t++]=x;
			int mx=0x80808080;
			for(int j=0;j<t;j++){
				list[j+t]=list[j];
				mx=max(mx,dp[list[j]]+min(j+1,t-j-1));
			}
			q.clear();
			q.push(N(0,dp[list[0]]));
			int adds=0;
			for(int j=1;j<2*t;j++){
				q.pop(j-t/2-1);
				adds++;
				ans=max(ans,dp[list[j]]+adds+q.ask());
				q.push(N(j,dp[list[j]]-adds));
			}
			dp[x]=max(dp[x],mx);
		}else if(!low[P[i]]){
			fa[P[i]]=x;
			dfs(P[i]);
			low[x]=min(low[x],low[P[i]]);
			if(low[P[i]]>dfn[x])ans=max(ans,dp[x]+dp[P[i]]+1),dp[x]=max(dp[x],dp[P[i]]+1);
		}else low[x]=min(low[x],dfn[P[i]]);
	}
	ans=max(ans,dp[x]);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0,k;i<m;i++){
		scanf("%d",&k);
		int last;
		scanf("%d",&last);
		for(int i=1,t;i<k;i++){
			scanf("%d",&t);
			add(last,t);add(t,last);
			last=t;
		}
	}
	dfs(1);
	printf("%d\n",ans);	
	return 0;
}