P4244 [SHOI2008]仙人掌图 II

P4244 [SHOI2008]仙人掌图 II

仙人掌求直径,和树一样最大+次大
处理环时,算一下环内两点距离+子树最大和,根节点此时的其他子树已确定的最大子树 用 环内一点距离+点最大子树更新

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e7;
inline LL Read(){
	LL x=0,f=1; char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0'&&c<='9')
	    x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
struct node{
	LL to,next;
}dis[maxn];
LL n,m,num,ans,tot;
LL dp[maxn],dep[maxn],low[maxn],dfn[maxn],a[maxn],head[maxn],fa[maxn],q[maxn];
inline void Add(LL u,LL v){
	dis[++num]=(node){v,head[u]},head[u]=num;
}
inline void Dp(LL u,LL v){
	LL len=dep[v]-dep[u]+1,j=len;
    for(int i=v;i!=u;i=fa[i])
	    a[j--]=dp[i]; a[j]=dp[u];
    for(LL i=1;i<=len;++i)
	    a[i+len]=a[i];
    LL hea=1,tail=1; 
	q[1]=1;
    for(LL i=2;i<=len*2;++i){
        while(hea<=tail&&i-q[hea]>len/2) 
		    hea++;
        ans=max(ans,a[i]+i+a[q[hea]]-q[hea]);
        while(hea<=tail&&a[q[tail]]-q[tail]<a[i]-i)
		    --tail;
        q[++tail]=i;
    }
    for(LL i=2;i<=len;i++)
        dp[u]=max(dp[u],a[i]+min(i-1,len-i+1));
}
void Tarjan(LL u){
	//printf("%lld
",u);
	low[u]=dfn[u]=++tot;
	for(LL i=head[u];i;i=dis[i].next){
		LL v=dis[i].to;
		if(v==fa[u])
		    continue;
		if(!dfn[v]){
			dep[v]=dep[u]+1,
			fa[v]=u;
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}else
		    low[u]=min(low[u],dfn[v]);
		if(low[v]>dfn[u]){
			ans=max(ans,dp[u]+dp[v]+1);
			dp[u]=max(dp[u],dp[v]+1);
	    }
	}
	for(LL i=head[u];i;i=dis[i].next){
		LL v=dis[i].to;
		if(fa[v]!=u&&dfn[u]<dfn[v])
		    Dp(u,v);
	}
}
int main(){
	n=Read(), m=Read();
	while(m--){
		LL kase=Read();
		LL pre=Read();
		for(LL i=2;i<=kase;++i){
			LL now=Read();
			Add(now,pre),Add(pre,now),
			pre=now;
		}
	}
	Tarjan(1);
	printf("%lld",ans);
	return 0;
}/*
15 3
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
5 2 14 9 15 10

8
*/
原文地址:https://www.cnblogs.com/y2823774827y/p/10201005.html