衡陽八中模擬:cave 圓方樹 Lca
阿新 • • 發佈:2018-11-06
衡陽八中模擬: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;
}