版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}