列表

详情


NC15433. 树

描述

给你一棵树,边权为1,有点权

需要支持两个操作:

1 x y z表示把树上x到y这条简单路径的所有点点权都加上z

2 x y表示查询与点x距离 <= 1的所有点里面的第y小点权

输入描述

第一行两个数n,m
第二行n个数表示每个点的点权
之后n-1行,每行两个数x,y表示x和y之间连有一条边
之后m行
每行为1 x y z或者2 x y形式
意义如上述

输出描述

输出m行,每行一个数表示答案
数据保证每次询问都存在答案

示例1

输入:

5 5
3 4 3 1 3
1 2
1 3
2 4
3 5
2 1 3
2 1 1
1 1 1 1
2 1 3
1 4 1 1

输出:

4
3
4

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 2185ms, 内存消耗: 103484K, 提交时间: 2021-07-09 12:16:35

/**
 * Author: yurzhang
 * Date: 2021/07/09
 */
#include <cstdio>

#define gc (pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),pa==pb)?EOF:*pa++)

const int N = 1000010;
const int MAXN = 2097162;
static char buf[100000], *pa = buf, *pb = buf;
inline int read() {
    int x = 0; char c = gc;
    while (c < '0' || c > '9') c = gc;
    while (c >= '0' && c <= '9')
        x = x * 10 + c - 48, c = gc;
    return x;
}

inline int lowbit(int x) {
    return x & -x;
}

int tot, stack[10], top;
inline int newNode() {
    if (top)
        return stack[top --];
    else return ++ tot;
}

int root[N], val[N], lc[N], rc[N], siz[N];
inline void up(int x) {
    siz[x] = siz[lc[x]] + siz[rc[x]] + 1;
}
inline void lr(int &x) {
    int y = rc[x];
    rc[x] = lc[y];
    lc[y] = x;
    siz[y] = siz[x];
    up(x); x = y;
}
inline void rr(int &x) {
    int y = lc[x];
    lc[x] = rc[y];
    rc[y] = x;
    siz[y] = siz[x];
    up(x); x = y;
}
inline void maintain(int &x, bool y) {
    if (y) {
        if (siz[rc[rc[x]]] > siz[lc[x]]) lr(x);
        else if (siz[lc[rc[x]]] > siz[lc[x]])
            rr(rc[x]), lr(x);
        else return;
    } else {
        if (siz[lc[lc[x]]] > siz[rc[x]]) rr(x);
        else if (siz[rc[lc[x]]] > siz[rc[x]])
            lr(lc[x]), rr(x);
        else return;
    } maintain(lc[x], false);
    maintain(rc[x], true);
    maintain(x, true);
    maintain(x, false);
}
void insert(int &now, int v) {
    if (now == 0) {
        now = newNode();
        val[now] = v;
        siz[now] = 1;
        lc[now] = rc[now] = 0;
    } else {
        ++ siz[now];
        if (val[now] <= v) {
            insert(rc[now], v);
            maintain(now, true);
        } else {
            insert(lc[now], v);
            maintain(now, false);
        }
    }
}
void erase(int &now, int v) {
    -- siz[now];
    if (val[now] == v) {
        if (lc[now] == 0 || rc[now] == 0) {
            stack[++ top] = now;
            now = lc[now] + rc[now];
        } else {
            int tmp = rc[now];
            while (lc[tmp]) tmp = lc[tmp];
            val[now] = val[tmp];
            erase(rc[now], val[tmp]);
        }
    } else if (val[now] < v)
        erase(rc[now], v);
    else erase(lc[now], v);
}
inline int getKth(int root, int k) {
    int now = root;
    while (now) {
        if (siz[lc[now]] + 1 == k)
            return val[now];
        if (siz[lc[now]] < k) {
            k -= siz[lc[now]] + 1;
            now = rc[now];
        } else now = lc[now];
    } return -1;
}

int n, m, v[N], nv[N], wt[N];
int opt, x, y, z;

inline void _add(int x, int v) {
    while (x <= n) {
        wt[x] += v;
        x += lowbit(x);
    }
}

inline void add(int l, int r, int v) {
    _add(l, v); _add(r + 1, -v);
}

inline int get(int x) {
    int res = 0;
    while (x) {
        res += wt[x];
        x -= lowbit(x);
    } return res;
}

int e, bg[N], nx[N << 1], to[N << 1];
inline void link(int u, int v) {
    to[++ e] = v;
    nx[e] = bg[u];
    bg[u] = e;
}

int fa[N], dep[N], ws[N], sz[N];
void dfs1(int now, int f) {
    fa[now] = f;
    dep[now] = dep[f] + 1;
    sz[now] = 1;
    int mx = -1;
    for (int i = bg[now]; i; i = nx[i])
        if (to[i] != f) {
            dfs1(to[i], now);
            sz[now] += sz[to[i]];
            if (sz[to[i]] > mx) {
                mx = sz[to[i]];
                ws[now] = to[i];
            }
        }
}

int cnt, tp[N], id[N];
void dfs2(int now, int top) {
    tp[now] = top;
    id[now] = ++ cnt;
    nv[cnt] = v[now];
    if (ws[now] == 0)
        return;
    dfs2(ws[now], top);
    for (int i = bg[now]; i; i = nx[i])
        if (to[i] != fa[now] && to[i] != ws[now]) {
            dfs2(to[i], to[i]);
            insert(root[now], v[to[i]]);
        }
}

inline void check(int x, int v) {
    if (x == tp[x] && fa[x]) {
        erase(root[fa[x]], get(id[x]));
        insert(root[fa[x]], get(id[x]) + v);
    }
}

void modify(int x, int y, int v) {
    while (tp[x] != tp[y]) {
        if (dep[tp[x]] > dep[tp[y]]) {
            check(tp[x], v);
            add(id[tp[x]], id[x], v);
            x = fa[tp[x]];
        } else {
            check(tp[y], v);
            add(id[tp[y]], id[y], v);
            y = fa[tp[y]];
        }
    } if (dep[x] > dep[y]) {
        check(y, v);
        add(id[y], id[x], v);
    } else {
        check(x, v);
        add(id[x], id[y], v);
    }
}

int query(int x, int y) {
    insert(root[x], get(id[x]));
    if (ws[x])
        insert(root[x], get(id[ws[x]]));
    if (fa[x])
        insert(root[x], get(id[fa[x]]));
    int res = getKth(root[x], y);
    erase(root[x], get(id[x]));
    if (ws[x])
        erase(root[x], get(id[ws[x]]));
    if (fa[x])
        erase(root[x], get(id[fa[x]]));
    return res;
}

int main() {
    n = read(); m = read();
    for (int i = 1; i <= n; ++ i)
        v[i] = read();
    for (int i = 1; i < n; ++ i) {
        x = read(); y = read();
        link(x, y); link(y, x);
    } dfs1(1, 0); dfs2(1, 1);
    for (int i = 1; i <= n; ++ i)
        _add(i, nv[i] - nv[i - 1]);
    while (m --) {
        opt = read(); x = read(); y = read();
        if (opt == 1) {
            z = read();
            modify(x, y, z);
        } else printf("%d\n", query(x, y));
    } return 0;
}

上一题