HDU7150. Static Query on Tree (2022杭电多校第2场1001)

HDU7150. Static Query on Tree (2022杭电多校第2场1001)

题意

给定一棵树,\(n\) 个结点。根为 \(1\),所有的结点只能走向其父亲结点。

\(q\) 次询问,每次询问给出 \(3\) 个结点集合 \(A,B,C\)。问树上有多少点满足如下条件:

  • 该点可以从集合 \(A\) 中的至少一个结点到达。
  • 该点可以从集合 \(B\) 中的至少一个结点到达。
  • 该点可以到达集合 \(C\) 中的至少一个结点。

分析

对于集合 \(A\) 中的一个点,它能到达的结点是包括他自己向上一直到根的路径。

对于集合 \(B\) 中的一个点,它能到达的结点是包括他自己向上一直到根的路径。

对于集合 \(C\) 中的一个点,它以及它的后代都能到达这个点。

实际上,问题转化为有多少个点同时满足上面三个性质。可以开一个线段树,对于集合 \(A\) 的对应点打上 \(a\) 标记,集合 \(B\) 的对应点打上 \(b\) 标记。最后统计对于 \(C\) 中的每一个点为根的子树,统计完一个点,消去以这个点为根的子树上的所有 \(a,b\) 标记。这可以使用树链剖分+线段树维护,注意每次询问都要清空所有标记,可以使用一个清空 tag 来保证复杂度。

代码

#include <iostream>
#include <vector>
#define now nodes[rt]
#define ls nodes[rt << 1]
#define rs nodes[rt << 1 | 1]
using namespace std;
const int maxn = 2e5 + 10;
int n, q;
vector<int> G[maxn];
int fa[maxn], son[maxn], dep[maxn], sz[maxn], dfn[maxn], rk[maxn], top[maxn];
int tot;
void init() {
    tot = 0;
}
void dfs(int u) {
    sz[u] = 1;
    dep[u] = dep[fa[u]] + 1;
    for (auto v : G[u]) {
        dfs(v);
        if (sz[v] > sz[son[u]])
            son[u] = v;
        sz[u] += sz[v];
    }
}
void dfs(int u, int t) {
    top[u] = t;
    dfn[u] = ++tot;
    rk[tot] = u;
    if (!son[u])
        return;
    dfs(son[u], t);
    for (auto v : G[u]) {
        if (v == son[u])
            continue;
        dfs(v, v);
    }
}
struct SegTree {
    struct Node {
        int l, r;
        int a, b, ab;
        int tag_a, tag_b, tag_cls;
    } nodes[maxn << 2];
    void build(int rt, int l, int r) {
        now = {l, r, 0, 0, 0, 0, 0, 0};
        if (l == r)
            return;
        int mid = l + r >> 1;
        build(rt << 1, l, mid);
        build(rt << 1 | 1, mid + 1, r);
    }
    void pushup(int rt) {
        now.a = ls.a + rs.a;
        now.b = ls.b + rs.b;
        now.ab = ls.ab + rs.ab;
    }
    void update_node_a(int rt) {
        now.tag_a = 1;
        now.a = now.r - now.l + 1;
        now.ab = now.b;
    }
    void update_node_b(int rt) {
        now.tag_b = 1;
        now.b = now.r - now.l + 1;
        now.ab = now.a;
    }
    void update_node_cls(int rt) {
        now.tag_cls = 1;
        now.a = now.b = now.ab = now.tag_a = now.tag_b = 0;
    }
    void pushdown(int rt) {
        if (now.tag_cls) {
            update_node_cls(rt << 1);
            update_node_cls(rt << 1 | 1);
            now.tag_cls = 0;
        }
        if (now.tag_a) {
            update_node_a(rt << 1);
            update_node_a(rt << 1 | 1);
            now.tag_a = 0;
        }
        if (now.tag_b) {
            update_node_b(rt << 1);
            update_node_b(rt << 1 | 1);
            now.tag_b = 0;
        }
    }
    void update(int rt, int L, int R, void (SegTree::*op)(int rt)) {
        if (L <= now.l && now.r <= R) {
            (this->*op)(rt);
            return;
        }
        pushdown(rt);
        if (L <= ls.r)
            update(rt << 1, L, R, op);
        if (R >= rs.l)
            update(rt << 1 | 1, L, R, op);
        pushup(rt);
    }
    int query(int rt, int L, int R) {
        if (L <= now.l && now.r <= R) {
            return now.ab;
        }
        pushdown(rt);
        int ans = 0;
        if (L <= ls.r)
            ans += query(rt << 1, L, R);
        if (R >= rs.l)
            ans += query(rt << 1 | 1, L, R);
        return ans;
    }
} seg;

void update_chain(int u, void (SegTree::*op)(int rt)) {
    int v = 1;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);
        seg.update(1, dfn[top[u]], dfn[u], op);
        u = fa[top[u]];
    }
    if (dep[u] > dep[v])
        swap(u, v);
    seg.update(1, dfn[u], dfn[v], op);
}

void update_tree(int u, void (SegTree::*op)(int rt)) {
    seg.update(1, dfn[u], dfn[u] + sz[u] - 1, op);
}

int query_tree(int u) {
    return seg.query(1, dfn[u], dfn[u] + sz[u] - 1);
}

void solve() {
    cin >> n >> q;
    for (int i = 2; i <= n; i++) {
        cin >> fa[i];
        G[fa[i]].push_back(i);
    }
    dfs(1);
    dfs(1, 1);
    seg.build(1, 1, n);
    while (q--) {
        int a, b, c, t;
        int ans = 0;
        cin >> a >> b >> c;
        for (int i = 0; i < a; i++) {
            cin >> t;
            update_chain(t, &SegTree::update_node_a);
        }
        for (int i = 0; i < b; i++) {
            cin >> t;
            update_chain(t, &SegTree::update_node_b);
        }
        for (int i = 0; i < c; i++) {
            cin >> t;
            ans += query_tree(t);
            update_tree(t, &SegTree::update_node_cls);
        }
        cout << ans << '\n';
        update_tree(1, &SegTree::update_node_cls);
    }
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}
posted @ 2022-07-22 17:08  聆竹听风  阅读(145)  评论(0)    收藏  举报