2752. 仙人掌图

题目链接

2752. 仙人掌图

如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus)。

所谓简单回路就是指在图上不重复经过任何一个顶点的回路。

image

举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6,5,4(7,8,9,10,2,3,7) 以及 (4,3,7,8,9,10,2,1,6,5,4),而 (2,3) 同时出现在前两个的简单回路里。

另外,第三张图也不是仙人图,因为它并不是连通图。

显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。

定义在图上两点之间的距离为这两点之间最短路径的距离。

定义一个图的直径为这张图相距最远的两个点的距离。

现在我们假定仙人图的每条边的权值都是 1,你的任务是求出给定的仙人图的直径。

输入格式

第一行包括两个整数 nm。其中 n 代表顶点个数,我们约定图中的顶点将从 1n 编号。

接下来一共有 m 行。代表 m 条路径。

每行的开始有一个整数 k,代表在这条路径上的顶点个数。接下来是 k1n 之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两个顶点的边。

一条路径上可能通过一个顶点好几次,比如对于第一个样例,第一条路径从 3 经过 8,又从 8 返回到了 3,但是我们保证所有的边都会出现在某条路径上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。

输出格式

只需输出一个数,这个数表示仙人图的直径长度。

数据范围

1n50000,
0m10000,
2k1000

输入样例1:

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

输出样例1:

8

输入样例2:

10 1 10 1 2 3 4 5 6 7 8 9 10

输出样例2:

9

样例解释

对于第一个样例:

如图,6 号点和 12 号点的最短路径长度为 8,所以这张图的直径为 8

image

解题思路

仙人掌,单调队列

求解仙人掌的直径
先将仙人掌转换为圆方树,考虑像求树的直径的 dp 算法,在树中,对于一条直径来说,其一定有一个最高点,且其通过最高点分为最长链和次长链两部分,dfs 枚举该最长链,如果最高点是圆点的话,可以发现对于原图,其有一种情况无法处理:当这个最高点在环上时,而这种情况恰好对于最高点是方点的情况,即当最高点是方点时,相当于处理到环的情况,假设 d[i] 为环上一点 i 的最长链,此时要求 d[i]+d[j]+ijij,ij/2)最大,即 d[i]+i+d[j]j 最大,d[i]+i 固定,即在 /2 的范围内找 d[j]j 的最大值,即滑动窗口问题

  • 时间复杂度:O(n+m)

代码

// Problem: 仙人掌图 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/2754/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=100005,M=3*N,inf=1e8; int n,new_n,m; int h[2][N],e[M],ne[M],w[M],idx; int dfn[N],low[N],timestamp; int fu[N],fw[N],fe[N],s[N],s_tot[N]; int res,f[N],d[N],q[N]; void add(int h[],int a,int b,int c) { e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } void build_circle(int x,int y,int z) { int sum=z; for(int i=y;i!=x;i=fu[i]) { s[i]=sum; sum+=fw[i]; } s[x]=s_tot[x]=sum; add(h[1],x,++new_n,0); for(int i=y;i!=x;i=fu[i]) { s_tot[i]=sum; add(h[1],new_n,i,min(s[i],sum-s[i])); } } void tarjan(int x,int from) { dfn[x]=low[x]=++timestamp; for(int i=h[0][x];~i;i=ne[i]) { int j=e[i]; if(!dfn[j]) { tarjan(j,i); fu[j]=x,fw[j]=w[i],fe[j]=i; low[x]=min(low[x],low[j]); if(dfn[x]<low[j])add(h[1],x,j,1); } else if(i!=(from^1))low[x]=min(low[x],dfn[j]); } for(int i=h[0][x];~i;i=ne[i]) { int j=e[i]; if(dfn[x]<dfn[j]&&fe[j]!=i)build_circle(x,j,w[i]); } } int dfs(int x) { int d1=0,d2=0; for(int i=h[1][x];~i;i=ne[i]) { int j=e[i]; int t=dfs(j)+w[i]; if(t>=d1)d2=d1,d1=t; else if(t>d2)d2=t; } f[x]=d1; if(x<=n)res=max(res,d1+d2); else { int sz=0; d[sz++]=-inf; for(int i=h[1][x];~i;i=ne[i])d[sz++]=f[e[i]]; for(int i=0;i<sz;i++)d[i+sz]=d[i]; int hh=0,tt=-1; for(int i=0;i<sz*2;i++) { if(hh<=tt&&i-q[hh]>sz/2)hh++; if(hh<=tt)res=max(res,d[i]+i+d[q[hh]]-q[hh]); while(hh<=tt&&d[i]-i>=d[q[tt]]-q[tt])tt--; q[++tt]=i; } } return f[x]; } int main() { memset(h,-1,sizeof h); scanf("%d%d",&n,&m); while(m--) { int k,x,y; scanf("%d%d",&k,&x); while(--k) { scanf("%d",&y); add(h[0],x,y,1); add(h[0],y,x,1); x=y; } } new_n=n; tarjan(1,-1); dfs(1); printf("%d",res); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16916808.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(115)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示