Codeforces 343D dsu on tree + 权值线段树

题意

传送门 Codeforces 343D

题解

离线处理。将操作按照时间顺序编号为 [ 0 , Q ) [0,Q) [0,Q),那么对于编号为 i i i 的查询操作,只需关注祖先节点及 i i i 本身的操作中,编号区间 [ 0 , i ) [0,i) [0,i) 内最大的灌水操作;与子孙节点及自身的操作中,编号区间 [ 0 , i ) [0,i) [0,i) 内最大的抽水操作;两者中编号最大的即查询的结果。

那么开两颗权值线段树分别维护祖先节点与子孙节点信息;当然,使用 s t d : : s e t std::set std::set 编码更加简单。应用 d s u   o n   t r e e dsu\ on\ tree dsu on tree,统计子孙节点信息,同时在 D F S DFS DFS 框架下统计祖先节点信息。总时间复杂度 O ( N log ⁡ 2 N ) O(N\log^2N) O(Nlog2N)

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
const int maxn = 500005, maxq = 500005, sg_size = 1 << 20;
struct SegmentTree
{
    
    
    int tree[sg_size];
    void init() {
    
     memset(tree, -1, sizeof(tree)); }
    void change(int a, int x, int k, int l, int r)
    {
    
    
        if (r - l == 1)
        {
    
    
            tree[k] = x;
            return;
        }
        int chl = (k << 1) + 1, chr = (k << 1) + 2, m = (l + r) >> 1;
        a < m ? change(a, x, chl, l, m) : change(a, x, chr, m, r);
        tree[k] = max(tree[chl], tree[chr]);
    }
    int ask(int a, int b, int k, int l, int r)
    {
    
    
        if (a <= l && r <= b)
            return tree[k];
        int chl = (k << 1) + 1, chr = (k << 1) + 2, m = (l + r) >> 1;
        if (b <= m)
            return ask(a, b, chl, l, m);
        if (m <= a)
            return ask(a, b, chr, m, r);
        return max(ask(a, b, chl, l, m), ask(a, b, chr, m, r));
    }
} P, C;
struct Operation
{
    
    
    int t, op;
};
int N, Q, sz[maxn], recOp[maxq], Res[maxq];
int clk, L[maxn], R[maxn], vs[maxn];
vector<int> G[maxn];
vector<Operation> O[maxn];
bool hv[maxn];

void rd(int &x)
{
    
    
    x = 0;
    char c = 0;
    for (; !isdigit(c); c = getchar())
        ;
    for (; isdigit(c); c = getchar())
        x = (x << 1) + (x << 3) + c - '0';
}

void _dfs(int u, int p)
{
    
    
    sz[u] = 1, vs[clk] = u, L[u] = clk++;
    for (auto &v : G[u])
        if (v != p)
            _dfs(v, u), sz[u] += sz[v];
    R[u] = clk;
}

void add_p(int u, bool a)
{
    
    
    for (auto &o : O[u])
        if (o.op == 1)
            P.change(o.t, a ? o.t : -1, 0, 0, Q);
}

void add_c(int u, bool a)
{
    
    
    for (auto &o : O[u])
        if (o.op == 2)
            C.change(o.t, a ? o.t : -1, 0, 0, Q);
}

void add(int u, int p, bool a)
{
    
    
    add_c(u, a);
    for (auto &v : G[u])
        if (v != p && !hv[v])
            rep(i, L[v], R[v]) add_c(vs[i], a);
}

void dfs(int u, int p, int keep)
{
    
    
    add_p(u, 1);
    int hvCh = -1, mx = -1;
    for (auto &v : G[u])
        if (v != p && sz[v] > mx)
            mx = sz[v], hvCh = v;
    for (auto &v : G[u])
        if (v != p && v != hvCh)
            dfs(v, u, 0);
    if (hvCh != -1)
        dfs(hvCh, u, 1), hv[hvCh] = 1;
    add(u, p, 1);
    for (auto &o : O[u])
        if (o.op == 3)
        {
    
    
            int t = o.t;
            Res[t] = C.ask(0, t, 0, 0, Q) < P.ask(0, t, 0, 0, Q);
        }
    if (hvCh != -1)
        hv[hvCh] = 0;
    if (!keep)
        add(u, p, 0);
    add_p(u, 0);
}

int main()
{
    
    
    rd(N);
    rep(i, 1, N)
    {
    
    
        int u, v;
        rd(u), rd(v);
        --u, --v;
        G[u].push_back(v), G[v].push_back(u);
    }
    rd(Q);
    rep(i, 0, Q)
    {
    
    
        int op, u;
        rd(op), rd(u);
        --u;
        recOp[i] = op;
        O[u].push_back(Operation{
    
    i, op});
    }
    _dfs(0, -1);
    P.init(), C.init();
    dfs(0, -1, 1);
    rep(i, 0, Q) if (recOp[i] == 3) printf("%d\n", Res[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/120212266