【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;
}