【AT3945】[ARC092D] Two Faced Edges(图论)

点此看题面

  • 给定一张(n)个点(m)条边的有向图。
  • 对于每条边,求将它反向这张图的强连通分量数是否变化。
  • (nle10^3,mle2 imes10^5)

情况分析

对于一条边(x ightarrow y),考虑它翻转带来的影响,其实只要考虑翻转前后(x)能否到达(y)以及(y)能否到达(x)

显然翻转前(x)一定能到达(y)(因为有这条边),而翻转后(x)还能到达(y),就等价于在原图中存在一条不经过这条边从(x)(y)的路径。

显然翻转后(y)一定能到达(x)(因为有这条边),而翻转前(y)能够到达(x),就等价于在原图中(y)能到达(x)

(DFS)

考虑我们枚举一个起点(x)出发(dfs),对于每个点(y)记录(x)两条选择后能到达它的出边。

如果(y)记录了至少一条出边说明(x)能到达(y),如果(y)记录了两条出边说明存在一条不经过(x)(y)的边(如果存在)由(x)(y)的路径。

最后枚举每条边根据求出的信息判一下就好了。

一个玄学的常数问题,如果用前向星存图会被卡,必须使用(vector)存图。

代码:(O(nm))

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
#define M 200000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].fr=x,e[ee].to=y)
using namespace std;
int n,m,ee,lnk[N+5];bool g[N+5][N+5],vis[N+5][N+5];struct edge {int x,y;}e[M+5];
int d[N+5];vector<int> to[N+5];vector<int>::iterator it;
namespace FastIO
{
	#define FS 100000
	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
	char oc,FI[FS],*FA=FI,*FB=FI;
	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}using namespace FastIO;
int v1[N+5],v2[N+5];I void dfs(CI x,CI c,CI o)
{
	if(x==o||v1[x]&&v2[x]) return;if(v1[x]) {if(v1[x]==c) return;v2[x]=c;}else v1[x]=c;//不能再过起点;每个点记录两条边
	for(RI i=0;i^d[x];++i) dfs(to[x][i],c,o);
}
int main()
{
	RI i,j;for(read(n,m),i=1;i<=m;++i) read(e[i].x,e[i].y),to[e[i].x].push_back(e[i].y),++d[e[i].x];
	RI sz;for(i=1;i<=n;++i)//枚举一个点出发
	{
		for(j=1;j<=n;++j) v1[j]=v2[j]=0;for(j=1;j<=d[i];++j) dfs(to[i][j-1],j,i);//枚举每条出边
		for(j=1;j<=n;++j) vis[i][j]=v1[j],g[i][j]=v2[j];//记录两信息
	}
	for(j=1;j<=m;++j) puts(g[e[j].x][e[j].y]^vis[e[j].y][e[j].x]?"diff":"same");return 0;//枚举每条边根据求得信息判断
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT3945.html