衡阳八中模拟:cave 圆方树 Lca

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvzelong2014/article/details/83627457

衡阳八中模拟:cave

题目大意

给定一张无自环重边的无向图。多次询问两个点是否可以通过简单路径走奇数步到达。

分析

两个点间的所有简单路径的并就是这两个点之间的所有点双。
考虑如果这两个点在同一个点双内。如果这个点双存在奇环,那么两个点一定可以走奇数步到达。(考虑一个奇环的两个方向,通过不同方向走的任意两个点的路径步数奇偶性不同,说明走过这个环可以走奇数步or偶数步,也就是可以任意改变奇偶性),偶环则不一定。
考虑对每个点双黑白染色。如果染色成功,那么说明是偶环,否则是奇环。
标解采用的做法是,点双缩点后判断两点间路径上是否存在某个点双内部有奇环。如果有,那么直接判断可以。否则的话随便找一颗生成树,判断两点间路径奇偶性即可。
我的做法是建出圆方树,对于方点,如果其代表的点双有奇环,赋值为1,否则对点双内的白点向方点连一条边权为0的边,黑点连1,每次判断两点间圆方树路径上是否存在点权为1的方点or路径边权异或值为1即可。

代码

#include<bits/stdc++.h>
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
const int N = 1e6 + 10;
int rt, be[N];
struct Edge {
	int to[N], nx[N], pr[N], tp; bool w[N];
	void add(int u, int v, bool W) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp; w[tp] = W;}
	void adds(int u, int v, bool w = 0) {add(u, v, w); add(v, u, w);}
};
struct Round_Square_Tree {
	Edge T; int fa[N], w[N], sz[N], de[N], ds[N], d[N]; bool D[N];
	void dfs1(int u, int f) {
		fa[u] = f; w[u] += w[f]; sz[u] = 1; de[u] = de[f] + 1;
		for(int i = T.pr[u], v; i; i = T.nx[i])
			if((v = T.to[i]) != f) {
				D[v] = D[u] ^ T.w[i];
				dfs1(v, u);
				sz[u] += sz[v];
				sz[ds[u]] < sz[v] ? ds[u] = v : 0;
			}
	}
	void dfs2(int u, int c) {
		d[u] = c; if(!ds[u]) return; dfs2(ds[u], c); 
		for(int i = T.pr[u]; i; i = T.nx[i]) 
			if(T.to[i] != ds[u] && T.to[i] != fa[u])
				dfs2(T.to[i], T.to[i]);
	}
	int lca(int u, int v) {
		for(;d[u] != d[v]; u = fa[d[u]]) de[d[u]] < de[d[v]] ? u ^= v ^= u ^= v : 0;
		return de[u] < de[v] ? u : v; 
	}
	bool Ck(int u, int v) {
		int c = lca(u, v), cnt = w[u] + w[v] - w[c] - w[fa[c]];
		return cnt ?: D[u] ^ D[v];
	}
}rst;
struct Tarjan {
	Edge G; int dfn[N], low[N], cu[N], st[N], col[N], vis[N], tot, tm, tp, C, cnt;
	bool Paint(int u, int c) {
		col[u] = c;
		for(int i = G.pr[u], v; i; i = G.nx[i])
			if(vis[v = G.to[i]] == cnt) {
				if(col[v] == -c) continue;
				if(col[v] == c) return false;
				if(!Paint(v, -c)) return false;
			}
		return true;
	}
	void dfs(int u, int fa) {
		dfn[u] = low[u] = ++tm; st[++tp] = u; be[u] = rt;
		for(int i = G.pr[u], v; i; i = G.nx[i]) 
			if((v = G.to[i]) != fa) {
				if(!dfn[v]) {
					dfs(v, u), low[u] = std::min(low[u], low[v]);
					if(low[v] >= dfn[u]) {
						cu[C = 1] = u; ++cnt;
						for(vis[u] = cnt; st[tp + 1] != v;) //标记当前块 
                       		vis[st[tp]] = cnt, cu[++C] = st[tp--];
                       	rst.w[++tot] = !Paint(u, cnt); //染色 
                       	for(int i = 1;i <= C; ++i)
                       		rst.T.adds(cu[i], tot, col[cu[i]] > 0);      	
					}
				}
				else low[u] = std::min(low[u], dfn[v]);
			}
	}
}tar;
int main() {
	freopen("cave.in","r",stdin);
	freopen("cave.out","w",stdout);
	int n = ri(), m = ri(); tar.tot = n;
	for(int i = 1;i <= m; ++i) tar.G.adds(ri(), ri());
	for(int i = 1;i <= n; ++i) if(!tar.dfn[i])
		rt = i, tar.dfs(i, 0), rst.dfs1(i, 0), rst.dfs2(i, i);
	for(int q = ri(); q--;) {
		int u = ri(), v = ri();
		if(be[u] != be[v]) puts("No");
		else puts(rst.Ck(u, v) ? "Yes" : "No");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/83627457
lca