【ARC092D】Two Faced Edges

题目

题目链接:https://atcoder.jp/contests/arc092/tasks/arc092_d
有一个 \(N\) 个点 \(M\) 条边的有向图。保证图中不存在重边和自环。
试判断将每条边反向,其他边不变的情况下,图中强连通分量的数量是否改变。
若改变,输出 diff,否则输出 same
\(1 \leq N \leq 10^3\)\(1 \leq M \leq 2 \times 10^5\)

思路

考虑 \(u\to v\) 这条边变向会如何改变强连通分量的数量:

  • 如果存在一条 \(v\to u\) 的路径,且变向后不存在 \(u\to v\) 的路径,那么强连通分量会少 \(1\)
  • 如果存在另一条 \(u\to v\) 的路径,且变向前不存在 \(v\to u\) 的路径,那么强连通分量会多 \(1\)

综上,如果强连通分量会改变,当且仅当“存在 \(v\to u\) 的路径”和“存在另一条 \(u\to v\) 的路径”中恰好满足一个。
是否存在 \(v\to u\) 的路径直接 bitset 优化传递闭包就可以了。而存在另一条 \(u\to v\) 的路径,等价于从 \(u\)\(v\)\(u\to v\) 这一条边不是必经边。那么把 \(u\) 的出边按正序和倒序分别枚举一次,各跑 dfs,对于所有点 \(v\) 记录 \(u\)\(v\) 的路径中第一条边的编号(或者到达的点的编号),如果两次记录的编号不同,说明存在另一条 \(u\to v\) 的路径。
时间复杂度 \(O(nm+\frac{n^3}{\omega})\)

代码

#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
using namespace std;

const int N=1010,M=200010;
int n,m,tot,head[N],pre[N],vis[N],ans[M];
vector<pair<int,int> > e[N];
bitset<N> a[N];

void dfs(int x,int tp,int tag)
{
	pre[x]^=tp; vis[x]=tag;
	for (int i=0;i<e[x].size();i++)
	{
		int v=e[x][i].fi;
		if (vis[v]!=tag) dfs(v,tp,tag);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		e[x].push_back(mp(y,i)); a[x][y]=1;
	}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			if (a[j][i]) a[j]|=a[i];
	for (int i=1;i<=n;i++)
	{
		memset(pre,0,sizeof(pre));
		int lim=e[i].size()-1;
		vis[i]=i*2;
		for (int j=0;j<=lim;j++) dfs(e[i][j].fi,e[i][j].fi,i*2);
		vis[i]=i*2+1;
		for (int j=lim;j>=0;j--) dfs(e[i][j].fi,e[i][j].fi,i*2+1);
		for (int j=0;j<=lim;j++)
		{
			int v=e[i][j].fi,id=e[i][j].se;
			ans[id]=(pre[v]>0)^a[v][i];
		}
	}
	for (int i=1;i<=m;i++)
		ans[i] ? cout<<"diff\n" : cout<<"same\n";
	return 0;
}
posted @ 2021-08-30 10:29  stoorz  阅读(60)  评论(0编辑  收藏  举报