Luogu4244 [SHOI2008]仙人掌图 II

Luogu4244 [SHOI2008]仙人掌图 II

传送门

Luogu

题解

题目要求的是仙人掌的直径,考虑在圆方树上\(dp\),等价于对于\(f_u\)表示\(u\)子树内的最长链的长度.

如果是圆点之间的连边,直接转移即可.

如果是一个环之间的转移,可以将转移系数赋到这个环的环顶上面.

一个环的转移,等同于是枚举环上面的点然后走这个点到顶的最短距离.

一个环的贡献,等同于是枚举两个点计算贡献,这个可以用单调队列维护.

代码

快读写错调了1h.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<iostream>
#include<set>
#include<map>
using namespace std;
#define mp make_pair
#define ll long long
#define re register
typedef pair<int,int> pii;
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi()
{
	int f=1,sum=0;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
const int N=400010;
int n,m,front[N],cnt,f[N],fa[N],low[N],dfn[N],Time,ans=1,dep[N],top,q[N],sta[N];
struct node{int to,nxt;}e[N<<1];
void Add(int u,int v){e[++cnt]=(node){v,front[u]};front[u]=cnt;}
void solve(int u,int v)
{
	int tot=0;
	for(int i=v;i!=u;i=fa[i])sta[++tot]=i;sta[++tot]=u;
	reverse(sta+1,sta+tot+1);
	for(int i=1;i<=tot;i++)sta[i+tot]=sta[i];
	int H=1,T=0;
	for(int i=1;i<=tot+tot;i++)
	{
		while(H<=T&&i-q[H]>tot/2)H++;
		if(H<=T)ans=max(ans,f[sta[i]]+f[sta[q[H]]]+i-q[H]);
		while(H<=T&&f[sta[i]]-i>f[sta[q[T]]]-q[T])T--;q[++T]=i;
	}
	for(int i=v;i!=u;i=fa[i])
		f[u]=max(f[u],f[i]+min(dep[i]-dep[u],dep[v]-dep[i]+1));
	for(int i=1;i<=tot+tot;i++)sta[i]=0,q[i]=0;
}
void dfs(int u,int ff)
{
	dfn[u]=low[u]=++Time;fa[u]=ff;dep[u]=dep[ff]+1;
	for(int i=front[u];i;i=e[i].nxt)
	{
		int v=e[i].to;if(v==ff)continue;
		if(!dfn[v]){dfs(v,u);low[u]=min(low[u],low[v]);}
		else low[u]=min(low[u],dfn[v]);
		if(dfn[u]<low[v]){ans=max(ans,f[u]+f[v]+1);f[u]=max(f[u],f[v]+1);}
	}
	for(int i=front[u];i;i=e[i].nxt)
	{
		int v=e[i].to;if(v==ff)continue;
		if(fa[v]!=u&&dfn[u]<dfn[v])solve(u,v);
	}
}
int main()
{
	n=gi();int k=gi();
	while(k--)
	{
		int p=gi()-1,u=gi();
		for(int i=1;i<=p;i++)
		{
			int v=gi();
			if(u){Add(u,v);Add(v,u);}
			u=v;
		}
	}
	dfs(1,0);
	printf("%d\n",ans);
	return 0;
}
posted @ 2020-06-01 15:29  fexuile  阅读(82)  评论(0编辑  收藏  举报