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\n",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
*/