您的位置:首页 > 其它

【搜索】[AtCoder Regular Contest 092 F]Two Faced Edges

2018-03-18 20:28 513 查看

题意:

给出一个有向图,对每条边都做一次询问:

反转这条边后,对原图的强连通分量是否有影响?

点的个数N≤1000N≤1000,边的个数M≤200000M≤200000

分析:

首先对于原图的任意一条边(u,v)(u,v)如果反转之后,对强连通分量无影响,则:

1、u是否能通过其他边到达v

2、v是否能到达u

这两个问题的答案必须相同。

其实是比较简单的性质,但很难往这边想,仔细想想就明白了。

对于第二个问题,我们只需要从每个点出发,对全图跑一次DFS记录哪些点能到即可,复杂度O(NM)O(NM)。

对于第一个问题,则稍微复杂一点:

对于一个点xx,我们将其所有出边的点设为y1,y2……yky1,y2……yk

我们进行如下操作:

从y1到yky1到yk每个点依次出发,设当前的点为yiyi

若当前的点未被标记,则标记为ii,若已有标记,则退出。

然后,再从ykyk到y1y1每个点依次出发,仍然设当前点为yiyi

和之前一样,只是要和上一次独立开来,用另一个数组存储标记。

若当前的点未被标记,则标记为ii,若已有标记,则退出。

这样一来,我们可以知道从xx出发,到达任意一个点时,所经过的最小出边序号和最大出边序号。很显然,若两个值相同,则说明只能通过一条出边到达该点。那么这样一来,我们可以对y1,y2……yky1,y2……yk依次判断,若到达改点的最小出边序号和最大出边序号,均为该出边本身,则说明不能从xx出发,经过其他边到达该点。

这样一来,每次最多也只会访问MM条边进行标记,最终的复杂度也为O(NM)O(NM)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 1010
#define MAXM 200010
using namespace std;
int n,m,u,v;
int id[MAXN][MAXN],ans1[MAXN][MAXN],ans2[MAXN][MAXN],q[MAXN][2];
int ans[MAXM];
vector<int> a[MAXN];
void dfs(int x,int fa){
ans1[fa][x]=1;
for(int i=0;i<a[x].size();i++)
if(ans1[fa][a[x][i]]==0)
dfs(a[x][i],fa);
}
void dfs1(int x,int tag,int flag){
q[x][flag]=tag;
for(int i=0;i<a[x].size();i++)
if(!q[a[x][i]][flag])
dfs1(a[x][i],tag,flag);
}
int main(){
SF("%d%d",&n,&m);
for(int i=0;i<m;i++){
SF("%d%d",&u,&v);
u--;
v--;
id[u][v]=i+1;
a[u].push_back(v);
}
for(int i=0;i<n;i++)
dfs(i,i);
for(int i=0;i<n;i++){
memset(q,0,sizeof q);
q[i][0]=q[i][1]=-1;
for(int j=0;j<a[i].size();j++)
if(!q[a[i][j]][0])
dfs1(a[i][j],j+1,0);
for(int j=a[i].size()-1;j>=0;j--)
if(!q[a[i][j]][1])
dfs1(a[i][j],j+1,1);
for(int j=0;j<a[i].size();j++)
if(q[a[i][j]][0]!=j+1||q[a[i][j]][1]!=j+1)
ans2[i][a[i][j]]=1;
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(ans1[j][i]==ans2[i][j]&&id[i][j])
ans[id[i][j]]=1;
for(int i=1;i<=m;i++){
if(ans[i]==1)
PF("same\n");
else
PF("diff\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: