HEOI&TJOI2016 树

标准意义上第一道非模板树剖题,虽然我并不认为它是树剖

另:这是一道水题,第二道本省省选题(菜的一批)

Description

link

题意简述:给一棵树,支持两种操作:

1.对一个节点打标记

2.求一个节点距离最近的直系祖先(就是根到它链上的那种节点)

定义:自己也算自己的祖先

Solution

[Begin ]

首先树和序列转化,求一波 (dfn)

整一棵线段树,维护这个序列

修改的时候就变成了了区间取 (max),这里不是那种纯 (max)

如果询问就变成了单点查询

这里有一个问题:我们在 (push\_down) (或者你叫它 (spread))的时候要取的是 (max),但是我们在 (push\_up) 的时候是维护的子树上面最小的深度编号

这样有点玄学剪枝的意味,但是正确性可以意会(毕竟是先取 (max) 再取 (min)

[Q.A.D ]

(P.S.) 博主知道是(QED)

(为啥我觉得不是树剖??)

Code


#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm {
inline int read() {
    int res = 0, f = 1;
    char k;
    while (!isdigit(k = getchar()))
        if (k == '-')
            f = -1;
    while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
    return res * f;
}
const int N = 1e5 + 10;
struct node {
    int l, r, maxx, add;
#define add(p) t[p].add
#define l(p) t[p].l
#define r(p) t[p].r
#define maxx(p) t[p].maxx
} t[N << 2];
struct edge {
    int to, nxt;
} e[N << 1];
int head[N], cnt, tim, id[N], dep[N], sz[N], son[N], top[N], fa[N], n, T;
inline void adde(int u, int v) {
    e[++cnt].nxt = head[u];
    e[cnt].to = v;
    return head[u] = cnt, void();
}
inline void dfs1(int x, int f) {
    fa[x] = f;
    dep[x] = dep[f] + 1;
    sz[x] = 1;
    for (int i = head[x]; i; i = e[i].nxt) {
        int t = e[i].to;
        if (t == f)
            continue;
        dfs1(t, x);
        sz[x] += sz[t];
        if (sz[t] > sz[son[x]])
            son[x] = t;
    }
    return;
}
inline void dfs2(int x, int topf) {
    id[x] = ++tim;
    top[x] = topf;
    if (!son[x])
        return;
    dfs2(son[x], topf);
    for (int i = head[x]; i; i = e[i].nxt) {
        int t = e[i].to;
        if (t == fa[x] || t == son[x])
            continue;
        dfs2(t, t);
    }
    return;
}
inline void push_up(int p) {
    maxx(p) = dep[maxx(p << 1)] < dep[maxx(p << 1 | 1)] ? maxx(p << 1) : maxx(p << 1 | 1);
    return;
}
inline void spread(int p) {
    if (add(p)) {
        maxx(p << 1) = dep[maxx(p << 1)] > dep[add(p)] ? maxx(p << 1) : add(p);
        maxx(p << 1 | 1) = dep[maxx(p << 1 | 1)] > dep[add(p)] ? maxx(p << 1 | 1) : add(p);
        add(p << 1) = dep[add(p << 1)] > dep[add(p)] ? add(p << 1) : add(p);
        add(p << 1 | 1) = dep[add(p << 1 | 1)] > dep[add(p)] ? add(p << 1 | 1) : add(p);
    }
    return add(p) = 0, void();
}
inline void build(int p, int l, int r) {
    l(p) = l;
    r(p) = r;
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    return push_up(p);
}
inline void change(int p, int l, int r, int d) {
    if (l <= l(p) && r(p) <= r) {
        maxx(p) = dep[maxx(p)] > dep[d] ? maxx(p) : d;
        add(p) = dep[add(p)] > dep[d] ? add(p) : d;
        return void();
    }
    spread(p);
    int mid = (l(p) + r(p)) >> 1;
    if (l <= mid)
        if (dep[d] > dep[maxx(p << 1)])
            change(p << 1, l, r, d);
    if (r > mid)
        if (dep[d] > dep[maxx(p << 1 | 1)])
            change(p << 1 | 1, l, r, d);
    return push_up(p);
}
inline int query(int p, int x) {
    if (l(p) == x && r(p) == x)
        return maxx(p);
    spread(p);
    int mid = (l(p) + r(p)) >> 1, ans = -1;
    if (x <= mid)
        return query(p << 1, x);
    else
        return query(p << 1 | 1, x);
}
signed main() {
    n = read(), T = read();
    for (int i = 1, u, v; i < n; ++i) u = read(), v = read(), adde(u, v);
    dfs1(1, 0), dfs2(1, 1), build(1, 1, n);
    change(1, id[1], id[1] + sz[1] - 1, 1);
    while (T--) {
        string s;
        cin >> s;
        int x = read();
        if (s[0] == 'Q')
            printf("%lld
", query(1, id[x]));
        if (s[0] == 'C')
            change(1, id[x], id[x] + sz[x] - 1, x);
    }
    return 0;
}
}  // namespace yspm
signed main() { return yspm::main(); 

原文地址:https://www.cnblogs.com/yspm/p/12382273.html