zoukankan      html  css  js  c++  java
  • 【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;//枚举每条边根据求得信息判断
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Object-c NSArray
    内存管理池
    Objuct-c 对象的初始化 存起器 属性 self和super 内存管理
    继承什么的
    Object C 多态性
    Objectvie
    (重点) 协议
    分类
    一张图了解Python
    转载 MySql常用查询语句(23种)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT3945.html
Copyright © 2011-2022 走看看