zoukankan      html  css  js  c++  java
  • 题解 CF555E Case of Computer Network

    题目传送门

    题目大意

    给出一个(n)个点(m)条边的无向图,有(q)次有向点对((s,t)),问是否存在一种方法定向每条边使得每个点对可以(s o t)

    (n,m,qle 2 imes 10^5)

    思路

    首先我们可以发现,一个边双连通分量里面肯定可以满足,因为任意两点之间都有两条及以上路径,于是可以一条过去,一条回来。于是,我们就可以先双连通分量缩点一下。

    接着我们发现缩点完之后一定是个森林,因为如果存在环的话一定还可以缩点。那我们就可以用树上差分解决这个问题了。具体的话对于点对((s,t)),显然(s o lca(s,t))应该是向上的,(lca(s,t) o t)应该是向下的。如果存在一个边既向上又向下那显然是矛盾的。

    于是,我们就可以在(Theta(nlog n))的时间复杂度内解决这个问题。(求lca)

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 400005 
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    bool vis[MAXN << 1];
    int n,m,q,s[MAXN],t[MAXN],sum[MAXN],dfn[MAXN],low[MAXN];
    struct SolveTree{
    	int up;//表示边双连通分量有多少个 
    	struct edge{
    		int v,nxt;
    	}e[MAXN << 1];
    	int toop = 1,Index,s1[MAXN],s2[MAXN],fa[MAXN][21],col[MAXN],dep[MAXN],head[MAXN];
    	void Add_Edge (int u,int v){
    		e[++ toop] = edge {v,head[u]};head[u] = toop;
    		e[++ toop] = edge {u,head[v]};head[v] = toop;
    	}	
    	void dfs (int u,int par){
    		col[u] = Index,fa[u][0] = par,dep[u] = dep[par] + 1;
    		for (Int i = 1;i <= 20;++ i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    		for (Int i = head[u];i;i = e[i].nxt){
    			int v = e[i].v;
    			if (v ^ par) dfs (v,u);
    		}
    	}
    	int LCA (int x,int y){
    		if (dep[x] < dep[y]) swap (x,y);
    		for (Int i = 20,dis = dep[x] - dep[y];~i;-- i) if (dis >> i & 1) x = fa[x][i];
    		if (x == y) return x;
    		else{
    			for (Int i = 20;~i;-- i) if (fa[x][i] ^ fa[y][i]) x = fa[x][i],y = fa[y][i];
    			return fa[x][0];
    		} 
    	}
    	bool Remain(int u){
    		for (Int i = head[u];i;i = e[i].nxt){
    			int v = e[i].v;
    			if (v ^ fa[u][0]){
    				if (!Remain (v) || (s1[v] && s2[v])) return 0;
    				s1[u] += s1[v],s2[u] += s2[v];
    			}
    		}
    		return 1;
    	}
    	void Solve (){
    		for (Int i = 1;i <= up;++ i) if (!col[i]) ++ Index,dfs (i,0);
    		for (Int i = 1;i <= q;++ i){
    			int u = s[i],v = t[i];
    			if (col[u] != col[v]) return puts ("No"),void ();
    			else{
    				int w = LCA (u,v);
    				s1[u] ++,s1[w] --,s2[v] ++,s2[w] --;
    			}
    		}
    		for (Int i = 1;i <= up;++ i) if (dep[i] == 1 && !Remain (i)) return puts ("No"),void ();
    		puts ("Yes");
    	}
    }T;
    struct CutTree{
    	struct edge{
    		int v,nxt;
    	}e[MAXN << 1];
    	int top = 1,Index,head[MAXN],col[MAXN];
    	void Add_Edge (int u,int v){
    		e[++ top] = edge {v,head[u]};head[u] = top;
    		e[++ top] = edge {u,head[v]};head[v] = top;
    	}
    	int id;
    	void Tarjan (int u,int fa){
    		dfn[u] = low[u] = ++ id;
    		for (Int i = head[u];i;i = e[i].nxt) if (e[i].v ^ fa){
    			int v = e[i].v;
    			if (!dfn[v]){
    				Tarjan (v,u),low[u] = min (low[u],low[v]);
    				if (low[v] > dfn[u]) vis[i] = vis[i ^ 1] = 1;//vis[i]表示该边是不是割边 
    			}
    			else low[u] = min (low[u],dfn[v]);
    		}
    	}
    	void dfs (int u){
    		col[u] = Index;
    		for (Int i = head[u],v;i;i = e[i].nxt) if (!col[v = e[i].v] && !vis[i]) dfs (v);
    	}
    	void build (){
    		read (n,m,q);
    		for (Int i = 1,u,v;i <= m;++ i) read (u,v),Add_Edge (u,v);
    		for (Int i = 1;i <= n;++ i) if (!dfn[i]) Tarjan (i,0);
    		for (Int i = 1;i <= n;++ i) if (!col[i]) ++ Index,dfs (i);T.up = Index;
    		for (Int i = 1;i <= n;++ i) for (Int j = head[i],v;j;j = e[j].nxt) if (col[v = e[j].v] > col[i]) T.Add_Edge (col[i],col[v]); 
    		for (Int i = 1;i <= q;++ i){
    		 read (s[i],t[i]),s[i] = col[s[i]],t[i] = col[t[i]];
    		 if (s[i] == t[i]) i --,q --; 
    		 } 
    	}
    }G;
    
    signed main(){ 
    	G.build(),T.Solve();
    	return 0;
    }
    
  • 相关阅读:
    Salesforce学习笔记(一)
    踏上Salesforce的学习之路(二)
    踏上Salesforce的学习之路(一)
    Salesforce注册开发者账号
    ubuntu下安装rtl8811cu/rtl8821cu网卡 Tplink WDN5200H网卡
    基于JRebel开发的MySQL Explain插件
    Logback配置解析
    基于springboot实现http响应异常信息国际化
    高并发场景下请求合并的实践
    后台开发常用mysql语句_v1.0
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13409720.html
Copyright © 2011-2022 走看看