[Luogu] 遥远的国度

https://www.luogu.org/problemnew/show/P3979

3种情况

 x=root,很显然此时应当查询整棵树

lca(root,x)!=x ,此时直接查询x的子树即可,与换根无关

lca(root,x)=x,此时我们应当查询与x相邻的节点中与root最近的点v在整棵树中的补集

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;

typedef long long ll;
typedef double dd;
const int maxn=200010;
const ll INF = (ll)1E14 + 9;

int h[maxn], n, m, top[maxn], lca[maxn][21], son[maxn], edge, sz[maxn], dep[maxn];
int L[maxn], R[maxn], root, num, x, y, tx, ty, t, opt;
ll val, a[maxn];

struct Edge {
    int to, ne;
} e[maxn * 2];

struct Seg {
    ll minn, same;
} seg[maxn << 2];

void close() {
    exit(0);
}

void addedge(int x,int y) {
    e[edge].to = y;
    e[edge].ne = h[x];
    h[x] = edge++;
}

void dfs(int k,int from) {
    sz[k] = 1;
    dep[k] = dep[from] + 1;
    son[k] = 0;
    for (int p=h[k]; p!=-1; p=e[p].ne) {
        int to = e[p].to;
        if (to == from) continue;
        lca[to][0] = k;
        for (int i=1; i<=20; i++)
            lca[to][i] = lca[lca[to][i-1]][i-1];
        dfs(to, k);
        sz[k] += sz[to];
        if (sz[to] > sz[son[k]]) son[k] = to;
    }
}

void build(int k,int from) {
    L[k] = ++num;
    top[k] = from;
    if (son[k]) build(son[k], from);
    for (int p=h[k]; p!=-1; p=e[p].ne) {
        int to = e[p].to;
        if (to != lca[k][0] && to != son[k])
            build(to, to);
    }
    R[k] = num;
}

int get_lca(int x,int y) {
    if (dep[x] < dep[y]) swap(x, y);
    int depth = dep[x] - dep[y];
    for (int i=20; i>=0; i--)
        if (depth & (1 << i))
            x = lca[x][i];
    if (x == y) return x;
    for (int i=20; i>=0; i--) {
        if (lca[x][i] != lca[y][i]) {
            x = lca[x][i];
            y = lca[y][i];
        }
    }
    return lca[x][0];
}

void pushup(int rt) {
    seg[rt].minn = min(seg[rt<<1].minn, seg[rt<<1|1].minn);
}

void same(int rt,ll val) {
    seg[rt].minn = val;
    seg[rt].same = val;
}

void pushdown(int rt) {
    if (seg[rt].same) {
        same(rt << 1, seg[rt].same);
        same(rt << 1 | 1, seg[rt].same);
        seg[rt].same = 0;
    }
}

void change(int L,int R,ll val,int l,int r,int rt) {
    if (L <= l && r <= R) {
        same(rt, val);
        return;
    }
    int mid = (l + r) >> 1;
    pushdown(rt);
    if (L <= mid)
        change(L,R,val,lson);
    if (mid + 1 <= R)
        change(L,R,val,rson);
    pushup(rt);
}

ll query(int L,int R,int l,int r,int rt) {
    if (L > R) return INF;
    if (L <= l && r <= R) {
        return seg[rt].minn;
    }
    int mid = (l + r) >> 1;
    pushdown(rt);
    ll ans = INF;
    if (L <= mid)
        ans = min(ans, query(L,R,lson));
    if (mid + 1 <= R)
        ans = min(ans, query(L,R,rson));
    pushup(rt);
    return ans;
}

void cc() {
    tx = top[x];
    ty = top[y];
    while (tx != ty) {
        if (dep[tx] < dep[ty]) {
            swap(x, y);
            swap(tx, ty);
        }
        change(L[tx], L[x], val, 1, n, 1);
        x = lca[tx][0];
        tx = top[x];
    }
    if (dep[x] < dep[y])
        swap(x, y);
    change(L[y], L[x], val, 1, n, 1);
}

void work() {
    if (root == x) {
        printf("%lld
", seg[1].minn);
        return;
    }
    t = get_lca(root, x);
    if (t != x) { 
        printf("%lld
", query(L[x], R[x], 1, n, 1));
        return;
    }
    int depth = dep[root] - dep[x] - 1;
    int haha = root;
    for (int i=20; i>=0; i--)
        if (depth & (1 << i))
            haha = lca[haha][i];
    printf("%lld
", min(query(1, L[haha] - 1, 1, n, 1), query(R[haha] + 1, n, 1, n, 1)) );
}

void init() {
    scanf("%d %d",&n,&m);
    memset(h, -1, sizeof(h));
    for (int i=1; i<=n-1; i++) {
        scanf("%d %d",&x, &y);
        addedge(x, y);
        addedge(y, x);
    }
    for (int i=1; i<=n; i++)
        scanf("%lld",&a[i]);
    dfs(1, 0);
    build(1, 1);
    for (int i=1; i<=n; i++)
        change(L[i], L[i], a[i], 1, n, 1);
    scanf("%d",&root);
    while (m--) {
        scanf("%d",&opt);
        if (opt == 1) scanf("%d",&root);
        if (opt == 2) {
            scanf("%d %d %lld",&x,&y,&val);
            cc();
        }
        if (opt == 3) {
            scanf("%d",&x);
            work();
        }
    }
}

int main () {
    init();
    close();
    return 0;
}
原文地址:https://www.cnblogs.com/shandongs1/p/8412648.html