zoukankan      html  css  js  c++  java
  • P3388 【模板】割点(割顶) 题解

    CSDN同步

    原题链接

    简要题意:

    给定一个图,求所有割点。

    割点(割顶)的定义:去掉该点整个图不连通。

    前置知识:

    强连通分量的 ( exttt{Tarjan}) 求法。

    不懂的可以先去了解下

    本题作为 ( exttt{Tarjan}) 求割点的模板题。

    首先,我们同样和求强连通分量一样,搞出一个 ( ext{dfn})( ext{low}).

    接着,你会发现这样的情况:

    如果 (x) 节点后面搜索树上的点 (y) 都满足 (low_y geq x),此时 (x) 不出意外 是一个割点。

    那 “意外” 指什么?

    想一下,如果是一条链的链顶,同样也满足 (low_y geq x(y in exttt{Subtree(x)})),但它不是割点。

    因此,我们从 (p) 节点开始搜索,就要判断清楚,(p) 到底是不是?

    应该是这样的:如果 (p) 有超过 (1) 个儿子,说明把它弄掉之后那 (>1) 个儿子走不通,所以 (p) 是割点。

    否则 (leq 1) 个儿子显然不是割点,这是要特殊判断的。

    答案如何记录?你注意到需要将答案去重,排序(因为一个点可能被它的每一个子树重复的记录多次)。那么显然就是用 ( exttt{set}) 解决!

    智商不够,数据结构来凑

    ( exttt{set}) 的到来凭空给时间增加一个 ( exttt{log}),但是没有关系,因为本来 ( exttt{Tarjan}) 就是线性的。

    (其实明明可以先哈希的,可是用 ( ext{STL}) 多快乐啊·)

    注意细节即可通过。

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

    实际得分:(100pts).

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+1;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int low[N],dfn[N],fa[N],n,m,cnt=0;
    bool vis[N]; set<int>s;
    vector<int>G[N];
    
    inline void Tarjan(int u) {
    	int sum=0; vis[u]=1; //sum 是子树个数
    	dfn[u]=low[u]=++cnt;
    	for(int i=0;i<G[u].size();i++) {
    		int v=G[u][i];
    		if(!vis[v]) {
    			fa[v]=u; sum++; Tarjan(v); //父亲节点用来判断起始点
    			low[u]=min(low[u],low[v]);
    			if(fa[u]!=u && low[v]>=dfn[u]) s.insert(u); //先把起始点排除
    		} else if(v!=fa[u]) low[u]=min(low[u],dfn[v]); //同样记录
    	} if(fa[u]==u && sum>=2) s.insert(u); //最后判断起始点
    }
    
    int main(){
    	n=read(),m=read(); while(m--) {
    		int x=read(),y=read();
    		G[x].push_back(y);
    		G[y].push_back(x);
    	} for(int i=1;i<=n;i++)
    		if(!vis[i]) {
    			fa[i]=i; //表示从 i 节点开始搜索
    			Tarjan(i);
    			cnt=0;
    		}
    	cout<<s.size()<<endl;
    	for(set<int>::iterator i=s.begin();i!=s.end();i++)
    		printf("%d ",*i); //记得是空格隔开,不是答案换行
    	return 0;
    }
    
    
  • 相关阅读:
    Eclipse的SVN插件与本地SVN客户端关联不上
    Oracle与MySQL连接配置
    树莓派实践项目
    20135333苏正生——信息安全系统设计基础第十四周学习总结
    《图解tcp/ip》读书笔记(二)
    解决VC几个编译问题的方法——好用
    《深入理解计算机系统》深入实践之——vim深入研究
    20135333苏正生——信息安全系统设计基础第十二周学习总结
    《图解tcp/ip》读书笔记(一)
    《你的灯亮着吗?:发现问题的真正所在》读书笔记2
  • 原文地址:https://www.cnblogs.com/bifanwen/p/12598627.html
Copyright © 2011-2022 走看看