仙人掌图2-仙人掌
题目描述
题解
分外环内和环外分别进行dp
推荐题解:https://www.cnblogs.com/chloris/p/11853320.html
仙人掌推荐博客:http://immortalco.blog.uoj.ac/blog/1955
代码实现
#include<bits/stdc++.h>
#define M 200009
using namespace std;
int pos[M],nxt[M],first[M],to[M],tot,a[M],f[M],dep[M],dp[M],ans,n,m,q[M];
int dfn[M],low[M],sign;
int read(){
char ch;
int f=1,re=0;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1;ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
void solve(int x,int y){
int cnt=dep[y]-dep[x]+1;//环上点的个数
for(int i=y;i!=x;i=f[i]) a[cnt--]=i;
a[cnt]=x,cnt=dep[y]-dep[x]+1;
for(int i=1;i<=cnt;i++) a[i+cnt]=a[i];//拆环成链
int l=1,r=1;
pos[1]=1,q[1]=dp[a[1]]-1;
for(int i=2;i<=2*cnt;i++){//这部分有点不懂
while(i-pos[l]>cnt/2&&l<=r)l++;
ans=max(ans,q[l]+dp[a[i]]+i);
while(l<=r&&q[r]<=dp[a[i]]-i)r--;
q[++r]=dp[a[i]]-i;
pos[r]=i;
}
for(int i=2;i<=cnt;i++)
dp[x]=max(dp[x],dp[a[i]]+min(i-1,cnt-i+1));
}
void tarjan(int x,int fa){
dfn[x]=low[x]=++sign;
dep[x]=dep[fa]+1,f[x]=fa;
for(int i=first[x];i;i=nxt[i]){
int v=to[i];
if(v==fa) continue;
if(!dfn[v]) tarjan(v,x),low[x]=min(low[x],low[v]);
else low[x]=min(low[x],dfn[v]);
if(dfn[x]<low[v]) ans=max(ans,dp[x]+dp[v]+1),dp[x]=max(dp[x],dp[v]+1);
}
for(int i=first[x];i;i=nxt[i]){
int v=to[i];
if(v==fa||f[v]==x||dfn[x]>dfn[v]) continue;
solve(x,v);
}
}
void add(int x,int y){
nxt[++tot]=first[x];
first[x]=tot;
to[tot]=y;
}
int main(){
int k,x,y;
n=read(),m=read();
for(int i=1;i<=m;i++){
k=read(),x=read();
for(int j=2;j<=k;j++){
y=read();
add(x,y),add(y,x);
x=y;
}
}tarjan(1,0);
printf("%d\n",ans);
return 0;
}