CF555E Case of Computer Network

https://www.luogu.com.cn/problem/CF555E

首先发现边双内的点可以互相到达
所以先缩边双,然后原图变成一棵树
对于经过一条边的路径,只能有一个方向
所以可以统计每条边,往上或往下的路径个数
这个可以直接树上差分,然后就可以了
看code吧
code:

#include<bits/stdc++.h>
#define N 400005
using namespace std;
struct edge {
	int v, nxt;
} e[N << 1];
int p[N], eid;
void init() {
	memset(p, -1, sizeof p);
	eid = 0;
}
void insert(int u, int v) {
	e[eid].v = v;
	e[eid].nxt = p[u];
	p[u] = eid ++;
}
int dfn[N], low[N], tot, top, bel[N], sta[N], in[N], sz;
void tar(int u, int ff) {// printf("  %d %d\n", u, ff);
	dfn[u] = low[u] = ++ tot;
	sta[++ top] = u; in[u] = 1;
	for(int i = p[u]; i + 1; i = e[i].nxt) {
		int v = e[i].v;
		if(i == ff) continue;
		if(!dfn[v]) tar(v, i ^ 1), low[u] = min(low[u], low[v]);
		else if(in[v]) low[u] = min(low[u], dfn[v]);		
	}
	if(dfn[u] == low[u]) {
		sz ++;
		while(sta[top] != u) {
			in[sta[top]] = 0;
			bel[sta[top --]] = sz;
		}
		in[sta[top]] = 0;
		bel[sta[top --]] = sz;
	}
}
int fa[N][21], sa[N], sb[N], vis[N], n, m, q, dep[N];
vector<int> a[N];
int faa[N];
int get(int x) {
	return (x == faa[x])? x : faa[x] = get(faa[x]);
}
void dfs(int u) {
	vis[u] = 1;
	dep[u] = dep[fa[u][0]] + 1;
	for(int i = 0; i < a[u].size(); i ++) {
		int v = a[u][i];
		if(vis[v]) continue;
		fa[v][0] = u,  dfs(v);
	}
}
int check(int u) { //printf("(%d \n", u);
//	printf("%d    %d %d  %d\n", u, sa[u], sb[u], !(sa[u] && sb[u]));
	for(int i = 0; i < a[u].size(); i ++) {
		int v = a[u][i];
		if(v == fa[u][0]) continue;
		if(!check(v)) return 0;
		sa[u] += sa[v], sb[u] += sb[v];
	}
//	printf("%d    %d %d  %d\n", u, sa[u], sb[u], !(sa[u] && sb[u]));
	return !(sa[u] && sb[u]);
}
int LCA(int u, int v) {
	if(dep[u] < dep[v]) swap(u, v);
	for(int i = 19; i >= 0; i --) if(dep[fa[u][i]] >= dep[v]) u = fa[u][i];
//	printf("- %d %d\n", u, v);
	if(u == v) return u;
	for(int i = 19; i >= 0; i --) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
	return fa[u][0];
}
int main() {
	init();
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= n; i ++) faa[i] = 1;
	for(int i = 1; i <= m; i ++) {
		int u, v;
		scanf("%d%d", &u, &v);
		insert(u, v), insert(v, u);		
		u = get(u), v = get(v);
		if(u != v) faa[u] = v;
	}
	for(int i = 1; i <= n; i ++) if(!dfn[i]) tar(i, N - 2);
//	printf("*****%d\n", sz);
//	for(int i = 1; i <= n; i ++) printf("%d ", bel[i]); printf("\n");
//	for(int i = 1; i <= n; i ++) printf("  %d %d\n", dfn[i], low[i]);
	for(int u = 1; u <= n; u ++) {
		for(int i = p[u]; i + 1; i = e[i].nxt) {
			int v = e[i].v;
			if(bel[u] != bel[v]) a[bel[u]].push_back(bel[v]);//, printf("%d --> %d\n", bel[u], bel[v]);
		}
	}
	for(int i = 1; i <= sz; i ++) if(!vis[i]) dfs(i);
	
//	for(int i = 1; i <= sz; i ++) printf(" &%d ", fa[i][0]); printf("\n");
	for(int j = 1; j <= 19; j ++)
		for(int i = 1; i <= sz; i ++)
			fa[i][j] = fa[fa[i][j - 1]][j - 1];
//	for(int j = 0; j <= 19; j ++) {
//		for(int i = 1; i <= sz; i ++) printf("  %d  ", fa[i][j]); printf("\n");
//	}
//	printf("                  * %d\n", LCA(1, 2));	
	while(q --) {
		int u, v;
		scanf("%d%d", &u, &v);
		if(get(u) != get(v)) {
			printf("No");
			return 0;
		}
		u = bel[u], v = bel[v];
		int lca = LCA(u, v);
	//	printf("  ****%d %d %d\n", u, v, lca);
		sa[u] ++, sb[v] --;
		sa[lca] --, sb[lca] ++;
	}
	for(int i = 1; i <= sz; i ++) if(!fa[i][0]) {
		if(!check(i)) { //printf("*");
			printf("No");
			return 0;
		}
	}
	printf("Yes");
	return 0;
}

刚写完的时候bug一堆,还是要好好智力康复一下啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值