1. 程式人生 > >衡陽八中模擬:cave 圓方樹 Lca

衡陽八中模擬:cave 圓方樹 Lca

衡陽八中模擬: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; }