1. 程式人生 > >【題解】CF#983 E-NN country

【題解】CF#983 E-NN country

  首先,我們從 u -> v 有一個明顯的貪心,即能向上跳的時候儘量向深度最淺的節點跳。這個我們可以用樹上倍增來維護。我們可以認為 u 貪心向上跳後不超過 lca 能跳到 u' 的位置, v 跳到 v' 的位置,這時只需要查詢一下是否有 u' -> v' 的直達公交線路就可以確定出答案了。

  如果 u 和 v 在一條鏈上,我們可以直接倍增獲得答案,所以以下討論均為 u != lca && v != lca 的情況。 若在節點 u 和 v 之間存在一條直達線路,說明有一條線路的起點在以 u 為根的子樹內,重點在以 v 為根的子樹內。即起點的dfs序 >= dfn[u] && <= dfn[u] + size[u] - 1, 終點的 dfs序 >= dfn[v] && <= dfn[v] + size[v] -1;這是一個二維限制的問題,暴力主席樹就可以搞定……

#include <bits/stdc++.h>
using namespace std;
#define maxn 450000
#define INF 99999999
#define CNST 20
int n, m, q, Mul[maxn][CNST], gra[maxn][CNST];
int dfn[maxn], dep[maxn], bits[30];
int tot, timer, root[maxn], fa[maxn], size[maxn];

int read()
{
    int x = 0, k = 1;
    char c; c = getchar();
    
while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * k; } struct edge { int cnp, to[maxn], last[maxn], head[maxn]; edge() { cnp = 2; } void add(int u, int v) { to[cnp]
= v, last[cnp] = head[u], head[u] = cnp ++; } }E1, G; struct edge1 { int u, v; edge1(int _u = 0, int _v = 0) { u = _u, v = _v; } friend bool operator <(const edge1& a, const edge1& b) { return (dfn[a.u] != dfn[b.u]) ? dfn[a.u] < dfn[b.u] : dfn[a.v] < dfn[b.v]; } }e[maxn]; struct node { int u, num; node(int _u = 0, int _num = 0) { u = _u, num = _num; } }; struct node1 { int sum, ls, rs; }T[maxn * 28]; void dfs(int u) { gra[u][0] = fa[u], dfn[u] = ++ timer; size[u] = 1; for(int i = 1; i < CNST; i ++) gra[u][i] = gra[gra[u][i - 1]][i - 1]; for(int i = E1.head[u]; i; i = E1.last[i]) { int v = E1.to[i]; dep[v] = dep[u] + 1; dfs(v); size[u] += size[v]; } } int dfs2(int u) { int lim = 0; for(int i = G.head[u]; i; i = G.last[i]) { if(u != G.to[i]) lim = (dep[lim] < dep[G.to[i]]) ? lim : G.to[i]; if(!lim && u != G.to[i]) lim = G.to[i]; } for(int i = E1.head[u]; i; i = E1.last[i]) { int v = E1.to[i]; int t = dfs2(v); if(u != t && t) lim = (dep[lim] < dep[t]) ? lim : t; if(!lim && u != t) lim = t; } Mul[u][0] = lim; return lim; } void dfs3(int u) { for(int i = 1; i < CNST; i ++) Mul[u][i] = Mul[Mul[u][i - 1]][i - 1]; for(int i = E1.head[u]; i; i = E1.last[i]) dfs3(E1.to[i]); } int LCA(int u, int v) { if(dep[u] < dep[v]) swap(u, v); for(int i = CNST - 1; ~i; i --) if(dep[gra[u][i]] >= dep[v]) u = gra[u][i]; for(int i = CNST - 1; ~i; i --) if(gra[u][i] != gra[v][i]) u = gra[u][i], v = gra[v][i]; return (u == v) ? u : gra[u][0]; } node Jump(int u, int fu) { bool flag = 0; int cnt = 0; if(dep[u] == dep[fu]) flag = 1; for(int i = CNST - 1; ~i; i --) { if(!Mul[u][i]) continue; if(dep[Mul[u][i]] <= dep[fu]) flag = 1; if(dep[Mul[u][i]] > dep[fu]) u = Mul[u][i], cnt += bits[i]; } if(!flag) return node(-1, 0); else return node(u, cnt); } void Ins(int &now, int pre, int l, int r, int x) { now = ++ tot; T[now] = T[pre]; T[now].sum ++; if(l == r) return; int mid = (l + r) >> 1; if(x <= mid) Ins(T[now].ls, T[pre].ls, l, mid, x); else Ins(T[now].rs, T[pre].rs, mid + 1, r, x); } bool Query(int now, int pre, int l, int r, int L, int R) { if(!now) return 0; if(L == l && R == r) return (T[now].sum - T[pre].sum); if(L > r || R < l) return 0; int mid = (l + r) >> 1; if(R <= mid) return Query(T[now].ls, T[pre].ls, l, mid, L, R); else if(L > mid) return Query(T[now].rs, T[pre].rs, mid + 1, r, L, R); else { if(Query(T[now].ls, T[pre].ls, l, mid, L, mid)) return 1; else return Query(T[now].rs, T[pre].rs, mid + 1, r, mid + 1, R); } } int main() { n = read(); bits[0] = 1; for(int i = 1; i < CNST; i ++) bits[i] = bits[i - 1] << 1; for(int i = 2; i <= n; i ++) { fa[i] = read(); E1.add(fa[i], i); } dep[1] = 1; dfs(1); m = read(); for(int i = 1; i <= m; i ++) { int u = read(), v = read(), lca = LCA(u, v); G.add(u, lca); G.add(v, lca); e[i] = edge1(u, v); } dfs2(1); dfs3(1); sort(e + 1, e + 1 + m); int last = 0; root[0] = tot = 1; for(int i = 1; i <= m; i ++) { while(last < dfn[e[i].u] - 1) T[root[last + 1] = ++ tot] = T[root[last]], last ++; Ins(root[dfn[e[i].u]], root[last], 1, n, dfn[e[i].v]); if(last != dfn[e[i].u]) last ++; } while(last + 1 <= n) T[root[last + 1] = ++ tot] = T[root[last]], last ++; q = read(); for(int i = 1; i <= q; i ++) { int u = read(), v = read(), lca = LCA(u, v); node a = Jump(u, lca), b = Jump(v, lca); int fu = a.u, fv = b.u; if(fu == -1 || fv == -1) { printf("-1\n"); continue; } if(u == lca || v == lca) { printf("%d\n", a.num + b.num + 1); continue; } int l1 = dfn[fu], r1 = dfn[fu] + size[fu] - 1; int l2 = dfn[fv], r2 = dfn[fv] + size[fv] - 1; int x = Query(root[r1], root[l1 - 1], 1, n, l2, r2); int y = Query(root[r2], root[l2 - 1], 1, n, l1, r1); printf("%d\n", a.num + b.num + 1 + !(x || y)); } return 0; }