P3388 【模板】割点(割顶)
以求割顶举例。
割顶:对于图中有一个点 ,如果删去它以及其连边后联通块个数增加,那么 即割顶。
先预处理出来 序,核心是求一个 数组。
:表示从 往上走能连接上最早的祖先的编号。
的计算过程是:
-
,也就是从 往儿子走再跳回去,这是对于树边的情况。
-
,注意,这是是 。原因是我至多只能跳一次,如果是 ,那就是跳多次,跳多次的话,我从中间断的话,他就不能再到 了,就不合法。这是对于反边的情况。
就比如这里。 而不是 ,原因是如果等于 的话,把 断掉就不能到 了,就不合法。
然后其实就是各种变形就求出不一样的东西来。
比如说割顶,当 时, 就是割顶,也就是儿子没有第二条路到当前节点以上,那么断了这个点儿子就到不了当前节点以上,那就是不连通了。
#include<bits/stdc++.h>
using namespace std;
const int N =1e6+10;
vector<int> g[N<<1];
int n,m,ind[N],low[N],dfn[N],ans,s,ans1[N],tot,num,cut[N],vis[N],now,root;
void Tarjan(int u){
low[u]=dfn[u]=++now,vis[u]=1;
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(!dfn[v]){
Tarjan(v);
if(u==root) s++;
else{
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]) cut[u]=1;
}
}
else
low[u]=min(low[u],dfn[v]);
}
}
int main()
{
cin>>n>>m;
for(int i=1,u,v;i<=m;i++){
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++){
s=0;
if(dfn[i]) continue;
root=i,now=0;
Tarjan(i);
ind[i]=s;
}
for(int i=1;i<=n;i++)
if(ind[i]>1) ans1[++tot]=i;
for(int i=1;i<=n;i++){
if(ind[i]!=0) continue;
if(cut[i]==1) ans1[++tot]=i;
}
sort(ans1+1,ans1+tot+1);
cout<<tot<<endl;
for(int i=1;i<=tot;i++) cout<<ans1[i]<<" ";
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现