LOJ10131. 「一本通 4.4 例 2」暗的連鎖【樹上差分】
阿新 • • 發佈:2018-11-06
solution
很簡單的題
你就考慮實際上是對每一個邊求出兩端節點分別在兩個子樹裡面的附加邊的數量
然後這個值是0第二次隨便切有m種方案,如果這個值是1第二次只有一種方案
如果這個值是2或者更大沒有方案
然後就可以直接統計答案了
那麼就對每一次查詢的邊
在兩個節點++,lca處-2就可以了
#include<bits/stdc++.h> using namespace std; const int N = 2e5 + 10; struct Edge { int v, nxt; } E[N << 1]; int n, m, ans = 0; int dep[N], head[N], tot = 0; int tag[N], fa[N][20]; void add(int u, int v) { E[++tot] = (Edge) {v, head[u]}; head[u] = tot; } void dfs(int u, int father) { dep[u] = dep[father] + 1; fa[u][0] = father; for (int i = 1; i <= 18; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int i = head[u]; i; i = E[i].nxt) { int v = E[i].v; if (v == father) continue; dfs(v, u); } } int LCA(int u, int v) { if (dep[u] < dep[v]) swap(u, v); int delta = dep[u] - dep[v]; for (int i = 18; i >= 0; i--) { if ((delta >> i) & 1) { u = fa[u][i]; } } if (u == v) return u; for (int i = 18; i >= 0; i--) { if (fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } } return fa[u][0]; } int solve(int u, int father) { int sum = tag[u]; for (int i = head[u]; i; i = E[i].nxt) { int v = E[i].v; if (v == father) continue; int w = solve(v, u); if (w == 1) ans++; if (w == 0) ans += m; sum += w; } return sum; } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif scanf("%d %d", &n, &m); for (int i = 2; i <= n; ++i) { int u, v; scanf("%d %d", &u, &v); add(u, v); add(v, u); } dfs(1, 0); for (int i = 1; i <= m; ++i) { int u, v; scanf("%d %d", &u, &v); tag[u]++; tag[v]++; tag[LCA(u, v)] -= 2; } solve(1, 0); printf("%d", ans); return 0; }