51nod1078 3条不相交的路径

51nod1078 3条不相交的路径

题目描述:

在这里插入图片描述
题目来源
代码参考自洛谷P6658

解题思路:

这是一道三连通分量分解的模板提,具体的分析可以看洛谷的链接。
通过分解三连通分量以后,这道题就变成了简单的并查集问题。
代码中的ans即三连通分量分解后的结果。

代码:

/*
代码大部分来源自洛谷P6658的作者
这里记录的是三连通分量的模板
*/
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

const int MaxN = 5e5 + 100, MaxM = 5e5 + 100;

struct graph_t {
	int cnte;
	int head[MaxN + 5], to[MaxM * 2 + 5], next[MaxM * 2 + 5];
	graph_t(){ cnte = 1; }
	void addEdge(int u, int v) {
		cnte++; to[cnte] = v;
		next[cnte] = head[u]; head[u] = cnte;
	}

};

struct union_find {
	int par[MaxN + 5];
	union_find() { memset(par, -1, sizeof(par)); }

	int find(int x) { return par[x] < 0 ? x : par[x] = find(par[x]); }

	void merge(int u, int v) {
		int p = find(u), q = find(v);
		if (p == q) return;
		par[p] += par[q];
		par[q] = p;
	}
};

int N, M;
graph_t Gr;

class two_edge_connect {
private:
	int low[MaxN + 5], dfn[MaxN + 5], dfc;
	int stk[MaxN + 5], tp;
	int bel[MaxN + 5], s;

	void dfs(int u, int fe) {
		low[u] = dfn[u] = ++dfc;
		stk[++tp] = u;
		for (int i = Gr.head[u]; i; i = Gr.next[i]) {
			if ((i ^ fe) == 1) continue;
			int v = Gr.to[i];
			if (dfn[v] == 0) {
				dfs(v, i);
				low[u] = min(low[u], low[v]);
			}
			else
				low[u] = min(low[u], dfn[v]);
		}
		if (low[u] == dfn[u]) {
			s++;
			for (;;) {
				int v = stk[tp--];
				bel[v] = s;
				if (u == v) break;
			}
		}
	}
public:
	void init() {
		memset(dfn, 0, sizeof(dfn));
		dfc = tp = s = 0;
		for (int i = 1; i <= N; i++)
			if (dfn[i] == 0)
				dfs(i, 0);
	}

	bool isbridge(int u, int v) {
		return bel[u] != bel[v];
	}
};

class three_edge_connect {
private:
	two_edge_connect bcc;
	union_find uf;
	int low[MaxN + 5], dfn[MaxN + 5], end[MaxN + 5], dfc;
	int deg[MaxN + 5];

	bool insubtree(int u, int v) {
		if (dfn[u] <= dfn[v] && dfn[v] <= end[u]) return true;
		return false;
	}

	void absorb(vector<int> &path, int u, int w = 0) {
		while (path.empty() == false) {
			int v = path.back();
			if (w > 0 && insubtree(v, w) == false) break;
			path.pop_back();
			deg[u] += deg[v] - 2;
			uf.merge(u, v);
		}
	}

	void dfs(int u, int fe, vector<int> &pu) {
		low[u] = dfn[u] = ++dfc;
		for (int i = Gr.head[u]; i; i = Gr.next[i]) {
			int v = Gr.to[i];
			if (u == v || bcc.isbridge(u, v) == true) continue;
			deg[u]++;
			if ((i ^ fe) == 1) continue;
			if (dfn[v] == 0) {
				vector<int> pv;
				dfs(v, i, pv);
				if (deg[v] == 2) pv.pop_back();
				if (low[v] < low[u]) {
					low[u] = low[v];
					absorb(pu, u);
					pu = pv;
				}
				else absorb(pv, u);
			}
			else {
				if (dfn[v] > dfn[u]) {
					absorb(pu, u, v);
					deg[u] -= 2;
				}
				else if (dfn[v] < low[u]) {
					low[u] = dfn[v];
					absorb(pu, u);
				}
			}
		}
		end[u] = dfc;
		pu.push_back(u);
	}

public:
	void init() {
		memset(dfn, 0, sizeof(dfn));
		memset(deg, 0, sizeof(deg));
		dfc = 0;
		bcc.init();
		for (int i = 1; i <= N; i++) {
			if (dfn[i] == 0) {
				vector<int> pi;
				dfs(i, 0, pi);
			}
		}
	}

	vector<vector<int> > getall() {
		vector<vector<int> > res(N), ans;
		for (int i = 1; i <= N; i++) {
			int x = uf.find(i);
			res[x - 1].push_back(i);
		}
		for (int i = 0; i < N; i++)
			if (res[i].empty() == false) ans.push_back(res[i]);
		return ans;
	}
};

void init() {
	scanf("%d%d", &N, &M);
	for (int i = 1; i <= M; i++) {
		int u, v;
		scanf("%d%d", &u, &v);
		Gr.addEdge(u, v);
		Gr.addEdge(v, u);
	}
}

int fa[MaxN];


int find(int x) {
	if (x == fa[x]) return x;
	return fa[x] = find(fa[x]);
}

void join(int x, int y) {
	fa[find(x)] = find(y);
}

void solve() {
	three_edge_connect tcc;
	tcc.init();
	vector<vector<int> > ans = tcc.getall();
	for (int i = 1; i <= N; i++) fa[i] = i;
	for (vector<int> x : ans) {
		for (int i = 1; i < x.size(); i++)
			join(x[i - 1], x[i]);
	}
	int q, a, b;
	scanf("%d", &q);
	while (q--) {
		scanf("%d%d", &a, &b);
		if (find(a) != find(b)) puts("No");
		else puts("Yes");
	}
}

int main() {
	//freopen("0.txt", "r", stdin);
	init();
	solve();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值