仙人掌图2-仙人掌

14 篇文章 0 订阅

仙人掌图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; 
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值