题目描述

给定一棵大小为 的树,每一个点上有一个物品,物品的属性

次操作,操作分两类,修改和询问。

  • 修改给定 , ,表示点 新增了一个属性为 的物品。

  • 询问给定 , , ,询问距离节点 最近的一个 "带有属性的物品" 的节点(下面称这种节点为关键节点)。

正解

如果是随机树的话,那么有一个小 trick,在两个点的 lca 计算贡献。

每一个点 维护一个动态开点的线段树,区间 维护的是距离点 最近的关键节点。

修改每一个点的时候暴力往上跳父亲(树高为 ),然后在祖先修改线段树。

查询的时候同样是暴力往上跳父亲,在祖先查询最近的关键节点。

复杂度为

现在考虑树不随机怎么做,常见套路是动态点分治。

先建出点分树,预处理每个分治中心到子节点的距离。

修改暴力往上跳,在点分树上的祖先修改。

查询类似,也是暴力往上跳就行。

复杂度同为

note

需要注意到的是,如果写动态开点线段树的话,空间复杂度是 (大概几个 G 吧)

于是我写的是平衡树 Splay,空间复杂度

你们猜猜看我的代码有多长?

#include <bits/stdc++.h>
#define N 100005
#define inf 1000000005

using namespace std;

int n, m;
int arr[N];
int head[N], nex[N << 1], to[N << 1], eVal[N << 1], ecnt;

inline int read() {
    int x = 0;
    char ch = getchar();
    while (!isdigit(ch))
        ch = getchar();
    while (isdigit(ch))
        x = x * 10 + ch - '0', ch = getchar();
    return x;
}
inline void addE(int u, int v, int w) {
    to[++ecnt] = v, eVal[ecnt] = w;
    nex[ecnt] = head[u], head[u] = ecnt;
}

void preDfs(int u, int fa) {
    for (int i = head[u], v; i; i = nex[i]) {
        v = to[i];
        if (v == fa)
            continue;
        preDfs(v, u);
    }
}

int totSi***Size, curRoot;
int fa[N], siz[N], dep[N], dis[30][N];

void getDist(int u, int fa) { // get size by the way
    siz[u] = 1;
    for (int i = head[u], v; i; i = nex[i]) {
        v = to[i];
        if (v == fa || ::fa[v])
            continue;
        dis[dep[curRoot]][v] = dis[dep[curRoot]][u] + eVal[i];
        getDist(v, u);
        siz[u] += siz[v];
    }
}
void getRoot(int u, int fa) {
    int maxSize = 0;
    for (int i = head[u], v; i; i = nex[i]) {
        v = to[i];
        if (v == fa || ::fa[v])
            continue;
        getRoot(v, u);
        if (siz[v] > maxSize)
            maxSize = siz[v];
    }
    maxSize = max(maxSize, totSize - siz[u]);
    if (maxSi***Si***Size = maxSize, curRoot = u;
}
void poiDiv(int u) {
    getDist(u, 0);
    for(int i = head[u], v; i; i = nex[i]) {
        v = to[i];
        if(::fa[v])
            continue;
        minSize = n;
        totSize = siz[v];
        getRoot(v, u);
        fa[curRoot] = u, dep[curRoot] = dep[u] + 1;
        poiDiv(curRoot);
    }
}

int totNode;
struct node {
    int ch[2], fa, key;
       int val, mic;
} a[N * 30];
int creNode(int key, int val) {
    int u = ++totNode;
    a[u].key = key, a[u].val = a[u].mic = val;
    return u;
}

struct BST {
#define lch(x) (a[x].ch[0])
#define rch(x) (a[x].ch[1])
#define par(x) (a[x].fa)
    int root;
    void link(int u, int f, bool ind) { par(u) = f, a[f].ch[ind] = u; }
    void update(int u) { a[u].mic = min(a[u].val, min(a[lch(u)].mic, a[rch(u)].mic)); }
    void rotate(int u) {
        int f = par(u), g = par(f);
        bool ind = (a[f].ch[1] == u);
        link(a[u].ch[!ind], f, ind), link(f, u, !ind), link(u, g, rch(g) == f);
        update(f);
    }
    void splay(int u, int tar = 0) {
        int f, g;
        while ((f = par(u)) != tar) {
            g = par(f);
            if (g != tar)
                rotate((rch(g) == f) ^ (rch(f) == u) ? u : f);
            rotate(u);
        }
        if (!tar)
            root = u;
        update(u);
    }
    void insert(int key, int val) {
        int u = root, las = 0;
        while (u && a[u].key != key)
            las = u, u = a[u].ch[key > a[u].key];
        if (!u) {
            u = creNode(key, val);
            link(u, las, a[u].key > a[las].key);
        } else {
            a[u].val = min(a[u].val, val);
        }
        splay(u);
    }
    int pre(int key) {
        int u = root, v = 0, maxKey = -1;
        while (u) {
            if (a[u].key < key) {
                if (maxKey < a[u].key)
                    v = u, maxKey = a[u].key;
                u = rch(u);
            } else {
                u = lch(u);
            }
        }
        return v;
    }
    int suc(int key) {
        int u = root, v = 0, minKey = N + 10;
        while (u) {
            if (a[u].key > key) {
                if (minKey > a[u].key)
                    v = u, minKey = a[u].key;
                u = lch(u);
            } else {
                u = rch(u);
            }
        }
        return v;
    }
    int query(int l, int r) {
        int lp = pre(l), rp = suc(r);
        splay(lp), splay(rp, lp);
        return a[lch(rp)].mic;
    }
    void init() {
        root = creNode(0, inf);
        link(creNode(N, inf), root, 1);
    }
#undef lch
#undef rch
#undef par
} Tr[N];

int main() {
    n = read(), m = read();
    for(int i = 1; i <= n; ++i)
        arr[i] = read();
    for (int i = 1, u, v, w; i < n; ++i) {
        u = read(), v = read(), w = read();
        addE(u, v, w), addE(v, u, w);
    }

    fa[1] = 1;
    curRoot = 1;
    poiDiv(1);
    fa[1] = 0;

    a[0].val = a[0].mic = inf;
    for (int i = 1; i <= n; ++i)
        Tr[i].init();

    for(int i = 1, u; i <= n; ++i) {
        u = i;
        while(u) {
            Tr[u].insert(arr[i], dis[dep[u]][i]);
            u = fa[u];
        }
    }

    for (int i = 1, op, x, l, r; i <= m; ++i) {
        op = read(), x = read(), l = read();
        if (op == 1) {
            int u = x;
            while(u) {
                Tr[u].insert(l, dis[dep[u]][x]);
                u = fa[u];
            }
        } else {
            r = read();
            int ans = inf, u = x;
            while(u) {
                ans = min(ans, dis[dep[u]][x] + Tr[u].query(l, r));
                u = fa[u];
            }
            if (ans >= inf) ans = -1;
            if(ans != -1) ans <<= 1;
            printf("%d\n", ans);
        }
    }
    return 0;
}