首页 > 其他分享 >[题解]AT_abc245_f [ABC245F] Endless Walk

[题解]AT_abc245_f [ABC245F] Endless Walk

时间:2023-10-02 13:44:39浏览次数:37  
标签:连通 idx int 题解 Walk ABC245F inline 节点 分量

思路

首先我们可以发现,在任意一个节点数量大于 \(1\) 的强连通分量中的点都满足条件。

所以,我们可以对这张图跑一边 TarJan。

但是这样是错的,因为我们还需要考虑节点数量为 \(1\) 的强连通分量。

如果这种连通分量能够到达任意一个节点数量大于 \(1\) 的强连通分量,那么,这个连通分量也满足条件。

所以,我们在缩完点后,反向建边,对于所有节点数量大于 \(1\) 的强连通分量为起点跑一边 DFS 即可。

因为每一个点最多会被遍历一次,所以时间复杂度为 \(\Theta(n + m)\)。

code

#include <bits/stdc++.h>
#define re register

using namespace std;

const int N = 2e5 + 10;
int n,m,ans;
int tim,num,dfn[N],low[N],sz[N],id[N];
bool vis[N];
stack<int> st;

struct edge{
	int idx,h[N],ne[N],e[N];
	
	inline void init(){
		memset(h,-1,sizeof(h));
	}
	
	inline void add(int a,int b){
		ne[idx] = h[a];
		e[idx] = b;
		h[a] = idx++;
	}
}g[2];

inline int read(){
	int r = 0,w = 1;
	char c = getchar();
	while (c < '0' || c > '9'){
		if (c == '-') w = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9'){
		r = (r << 1) + (r << 3) + (c ^ 48);
		c = getchar();
	}
	return r * w;
}

inline void tarjan(int u){
	dfn[u] = low[u] = ++tim;
	vis[u] = true;
	st.push(u);
	for (re int i = g[0].h[u];~i;i = g[0].ne[i]){
		int j = g[0].e[i];
		if (!dfn[j]){
			tarjan(j);
			low[u] = min(low[u],low[j]);
		}
		else if (vis[j]) low[u] = min(low[u],low[j]);
	}
	if (dfn[u] == low[u]){
		int x;
		num++;
		do{
			x = st.top();
			st.pop();
			sz[num]++;
			id[x] = num;
			vis[x] = false;
		}while (x != u);
	}
}

inline void dfs(int u){
	vis[u] = true;
	for (re int i = g[1].h[u];~i;i = g[1].ne[i]){
		int j = g[1].e[i];
		if (vis[j]) continue;
		dfs(j);
	}
}

int main(){
	g[0].init();
	g[1].init();
	n = read();
	m = read();
	for (re int i = 1;i <= m;i++){
		int a,b;
		a = read();
		b = read();
		g[0].add(a,b);
	}
	for (re int i = 1;i <= n;i++){
		if (!dfn[i]) tarjan(i);
	}
	for (re int u = 1;u <= n;u++){
		for (re int i = g[0].h[u];~i;i = g[0].ne[i]){
			int j = g[0].e[i];
			if (id[u] != id[j]) g[1].add(id[j],id[u]);
		}
	}
	memset(vis,false,sizeof(vis));
	for (re int u = 1;u <= num;u++){
		if (sz[u] > 1) dfs(u);
	}
	for (re int u = 1;u <= num;u++){
		if (vis[u]) ans += sz[u];
	}
	printf("%d",ans);
	return 0;
}

标签:连通,idx,int,题解,Walk,ABC245F,inline,节点,分量
From: https://www.cnblogs.com/WaterSun/p/AT_abc245_f.html

相关文章

  • CSES.1141 C++题解
    题意传送门有一个长度为\(n\)的歌单,问最长多少首歌互不相同?每首歌用一个\(1-10^9\)的整数表示。样例输入812132742样例输出5算法双指针算法。桶思想。对于歌单中重复出现的数,可以用桶来存储。定义两个指针i,j,i指向大数,j指向小数。当出现某个桶的数大于1时,则......
  • CF1878C Vasilije in Cacak 题解
    题目传送门简化题意有\(t\)组询问,每次询问是否能从\(1\simn\)中选择\(k\)个数使得它们的和为\(x\)。解法考虑临界情况,从\(1\simn\)中选择最小的\(k\)个数时和为\(\sum\limits_{i=1}^ki=\dfrac{(k+1)k}{2}\),从\(1\simn\)中选择最大的\(k\)个数时和为\(......
  • Codeforces 1765H 题解
    题目大意题目大意给定一个\(n\)个点和\(m\)条边的有向图,并给定\(p_1,p_2,\cdots,p_n\)表示第\(i\)个点的拓扑序必须小于等于\(p_i\),求出每个点的最小拓扑序。题解题解题目要求拓扑序尽量小,转换一下就是在反图上拓扑序尽量大。考虑拓扑排序,当一个点不得不入队......
  • UVA10054 The Necklace 题解
    好可恶一道题,怎么没人告诉我输出之间有空行(思路是先抽象成图,然后跑一边dfs记录边的前后顺序。对于不能成环的情况,只需要再开个数组记录度数判断奇点即可。若存在奇点则break掉,剩下的跑dfs、//producedbymiya555//stupidmistakes:1.多测要清空2.输出之间有空行//ideas:d......
  • 题解 hdu 1269 迷宫城堡
    找点图论练习题写,发现hdu又寄了,那就发到blog里吧。思路:tarjan缩点判断DAG中点数是否为1。若是,则该图为强连通图。 //producedbymiya555//stupidmistakes:多测记得清空//ideas:tarjan模板#include<bits/stdc++.h>usingnamespacestd;constintN=10010;intn,m,low[......
  • 题解 小 a 和 uim 之大逃离
    题目链接首先可以想到设状态\(k_1,k_2\)表示小\(a\)和小\(uim\)分别表示他们目前取得的得分,那么最终的答案便是\(k_1=k_2\)的时候。但是这样设置状态的复杂度无疑是高的。并且十分浪费,所以考虑设\(z\)表示\(k_1-k_2\)的值。那么\(z=0\)就是答案。接着考虑如何处......
  • SP9494 ZSUM - Just Add It 题解
    题目传送门前置知识快速幂解法推式子:\(\begin{aligned}Z_n+Z_{n-1}-2Z_{n-2}&=(Z_n-Z_{n-2})+(Z_{n-1}-Z_{n-2})\\&=(S_n+Q_n-S_{n-2}-Q_{n-2})+(S_{n-1}+Q_{n-1}-S_{n-2}-Q_{n-2})\\&=((n-1)^k+n^k+(n-1)^{n-1}+n^n)+((n-1)^k+(n-1)^{n-1})\\&=n^n+n^k+......
  • P2951 [USACO09OPEN] Hide and Seek S 题解
    Problem题目概述给你一个无向图,边权都为\(1\),求:离\(1\)号点最远的点的编号、最远的距离、有几个点是离\(1\)号点最远的。思路直接用:优先队列\(BFS\),先求出\(1\)号点到每个点的最短路,存到\(dis\)数组中,然后再求\(max(dis[i])\),就搞定了。错误原因审题&做法错......
  • P1144 最短路计数 题解
    Problem考察算法:拓扑排序+\(DP\)+\(Dijkstra\)。题目简述给出一个无向无权图,问从顶点\(1\)开始,到其他每个点的最短路有几条。思路先求出\(1\)号点到每个点的最短路\(d_i\)。分析每条边$(x,y)$:如果d[x]+1==d[y]:这条边有用。将所有有用的边拓扑排序......
  • [POI2003] Monkeys 题解
    [POI2003]Monkeys题解正着做貌似不好做,发现猴子是否掉落取决于“最后一根稻草”,也就是最后撒手的那个猴子,那我们考虑倒着把猴子网拼回去。这样,每群猴子掉落的时刻就是与\(1\)号猴子连通的时刻。利用并查集可以维护猴子的连通性,但是怎么更新答案呢?这里用vector进行了一个猴......