4539: [Hnoi2016]树

4539: [Hnoi2016]树

链接

分析:

  主席树+倍增。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#define pa pair<int,int>
using namespace std;
typedef long long LL;
#define int LL
inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 100005;
struct Edge { int to, nxt; } e[N << 1];
struct OPT { int l, r, fa, rt; } q[N];
int head[N], dfn[N], st[N], ed[N], pos[N], fa[N][20], siz[N], f[N][20], g[N][20], d1[N], d2[N];
set< pa > s;
int En, Index, NowIndex, n;

inline void add_edge(int u,int v) {
    ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En;
    ++En; e[En].to = u, e[En].nxt = head[v]; head[v] = En;
}
struct SegmentTree{
    int sum[N * 20], ls[N * 20], rs[N * 20], Root[N], TreeIndex;
    void Insert(int l,int r,int &now,int pre,int p) {
        if (!now) now = ++TreeIndex;
        sum[now] = sum[pre] + 1;
        if (l == r) return ;
        int mid = (l + r) >> 1;
        if (p <= mid) {
            rs[now] = rs[pre];
            Insert(l, mid, ls[now], ls[pre], p);
        } else {
            ls[now] = ls[pre];
            Insert(mid + 1, r, rs[now], rs[pre], p);
        }
    }
    int query(int l,int r,int H,int T,int k) {
        if (l == r) return l;
        int mid = (l + r) >> 1;
        if (k <= sum[ls[T]] - sum[ls[H]]) return query(l, mid, ls[H], ls[T], k);
        else return query(mid + 1, r, rs[H], rs[T], k - (sum[ls[T]] - sum[ls[H]]));
    }
}T;
void dfs(int u) {
    d1[u] = d1[fa[u][0]] + 1;
    st[u] = ++Index; pos[Index] = u; siz[u] = 1;
    for (int i = 1; i <= 19; ++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].to;
        if (v == fa[u][0]) continue;
        fa[v][0] = u;
        dfs(v);
        siz[u] += siz[v];
    }
    ed[u] = Index;
}
int LCA1(int u,int v) {
    if (d1[u] < d1[v]) swap(u, v);
    int d = d1[u] - d1[v];
    for (int i = 19; ~i; --i) if ((d >> i) & 1) u = fa[u][i];
    if (u == v) return u;
    for (int i = 19; ~i; --i) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
    return fa[u][0];
}
int getdis(int x,int y) {
    return d1[x] + d1[y] - d1[LCA1(x, y)] * 2;
}
void add(int id) {
    int x = read(), y = read(), z;
    q[id].l = NowIndex, q[id].r = (NowIndex += siz[x]) - 1, q[id].rt = x;
    set< pa > :: iterator it = s.lower_bound(pa(y, 0)); z = q[it->second].rt;
    q[id].fa = T.query(1, n, T.Root[st[z] - 1], T.Root[ed[z]], y - q[it->second].l + 1);
    f[id][0] = it->second, g[id][0] = getdis(q[id].fa, z) + 1;
    d2[id] = d2[it->second] + 1;
    for (int i = 1; i <= 19; ++i) f[id][i] = f[f[id][i - 1]][i - 1], g[id][i] = g[id][i - 1] + g[f[id][i - 1]][i - 1];
    s.insert(pa(q[id].r, id));
}
int LCA2(int u,int v,int tu,int tv) {
    if (d2[u] < d2[v]) swap(u, v), swap(tu, tv);
    int ans = 0, t = u, d = d2[u] - d2[v];
    for (int i = 19; ~i; --i) if ((d >> i) & 1) ans += g[u][i], u = f[u][i];
    if (u == v) {
        d --; ans = 0; u = t; 
        for (int i = 19; ~i; --i) if ((d >> i) & 1) ans += g[t][i], t = f[t][i];
        ans += getdis(q[t].fa, tv) + 1 + getdis(tu, q[u].rt);
        return ans;
    }
    ans += getdis(tu, q[t].rt) + getdis(tv, q[v].rt);
    for (int i = 19; ~i; --i) if (f[u][i] != f[v][i]) ans += g[u][i] + g[v][i], u = f[u][i], v = f[v][i];
    ans += getdis(q[u].fa, q[v].fa) + 2;
    return ans;
}
void Ask() {
    int u = read(), v = read(), ans, iu, iv, tu, tv;
    iu = s.lower_bound(pa(u, 0))->second, iv = s.lower_bound(pa(v, 0))->second;
    tu = T.query(1, n, T.Root[st[q[iu].rt] - 1], T.Root[ed[q[iu].rt]], u - q[iu].l + 1);
    tv = T.query(1, n, T.Root[st[q[iv].rt] - 1], T.Root[ed[q[iv].rt]], v - q[iv].l + 1);
    if (iu != iv) ans = LCA2(iu, iv, tu, tv);
    else ans = getdis(tu, tv);    
    printf("%lld\n", ans);
}
signed main() {
    n = read();int m = read(), Q = read();
    for (int i = 1; i < n; ++i) add_edge(read(), read());
    dfs(1);
    for (int i = 1; i <= n; ++i) 
        T.Insert(1, n, T.Root[i], T.Root[i - 1], pos[i]);
    NowIndex = n + 1;
    s.insert(pa(n, 1)); q[1].l = 1, q[1].r = n, q[1].rt = 1, q[1].fa = 0;
    for (int i = 1; i <= m; ++i) add(i + 1);
    while (Q --) Ask();
    return 0;
}

 

posted @ 2019-03-11 22:38  MJT12044  阅读(119)  评论(0编辑  收藏  举报