CF1017G The Tree

传送门


思路

(%%% lby大佬爆切此题)

对于这种能延迟生效的东西,第一考虑就是打标记

先考虑操作 1:我们假设给所有点一个初始点值 \(-1\),当要指定一个点 \(x\) 进行操作 1 时,我们将 \(x\) 的点权加一,因此, \(x\) 的点值实际上代表着它向自己的子树传递的次数

再考虑查询:当询问 \(x\) 的颜色时,我们考虑求出 \(x\) 开始的链上最大后缀 \(suf\),当有 \(suf\ge 0\) 时,代表 \(x\) 就是黑色;反之为白色

最后再考虑操作 2:一个朴素的想法就是将 \(x\) 子树所有点的点权都变回 \(-1\)。但有个问题,因为 \(x\) 的后缀依然有可能 \(\ge 0\)(从它的祖先传递下来的),因此我们要对 \(x\) 的点权减去一个数,实际上就是减去 \(suf(x)+1\),这样 \(x\) 的最大后缀就能保持为 \(-1\)

上面的操作用 树链剖分+线段树(维护区间和、区间最大后缀),可以做到 \(O(n\log^2 n)\)


代码

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = e[i].nxt)
inline int reads()
{
    int sign = 1, re = 0; char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
    while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
    return sign * re;
}
int n, m;
struct Node
{
    int to, nxt;
}e[200005]; int he[100005];
inline void Edge_add(int u, int v)
{
    static int cnt = 0;
    e[++cnt] = (Node){v, he[u]};
    he[u] = cnt;
}
int sz[100005], fa[100005], hs[100005], hr[100005], in[100005], out[100005], icnt;
void dfs1(int now)
{
    sz[now] = 1;
    PFOR(i, now)
    {
        int to = e[i].to;
        if(to == fa[now]) continue;
        fa[to] = now;
        dfs1(to);
        sz[now] += sz[to];
        if(sz[to] > sz[hs[now]]) hs[now] = to;
    }
}
void dfs2(int now)
{
    in[now] = ++icnt;
    if(hs[fa[now]] == now) hr[now] = hr[fa[now]];
    else hr[now] = now;
    if(hs[now]) dfs2(hs[now]);
    PFOR(i, now)
    {
        int to = e[i].to;
        if(to == fa[now] || to == hs[now]) continue;
        dfs2(to);
    }
    out[now] = icnt;
}
namespace Seg_Tree
{
    struct Tree
    {
        int sum, suf;
        Tree operator + (Tree b) {return (Tree){sum + b.sum, std::max(b.suf, b.sum + suf)};}
    }tr[400005];
    bool tag[400005];
    #define ls (now << 1)
    #define rs ((now << 1) | 1)
    inline void up(int now) {tr[now] = tr[ls] + tr[rs];}
    inline void down(int now, int l, int r)
    {
        if(tag[now])
        {
            int mid = (l + r) >> 1;
            tr[ls].suf = tr[rs].suf = -1;
            tr[ls].sum = l - mid - 1, tr[rs].sum = mid - r;
            tag[ls] = tag[rs] = 1;
            tag[now] = 0;
        }
    }
    void build(int now, int l, int r)
    {
        if(l == r)
        {
            tr[now] = (Tree){-1, -1};
            return;
        }
        int mid = (l + r) >> 1;
        build(ls, l, mid), build(rs, mid + 1, r);
        up(now);
    }
    void modify(int now, int l, int r, int to, int val)
    {
        if(l == r)
        {
            tr[now].sum += val, tr[now].suf += val;
            return;
        }
        down(now, l, r);
        int mid = (l + r) >> 1;
        if(to <= mid) modify(ls, l, mid, to, val);
        else modify(rs, mid + 1, r, to, val);
        up(now);
    }
    void cover(int now, int l, int r, int L, int R)
    {
        if(L <= l && r <= R)
        {
            tr[now].sum = l - r - 1;
            tr[now].suf = -1;
            tag[now] = 1;
            return;
        }
        down(now, l, r);
        int mid = (l + r) >> 1;
        if(L <= mid) cover(ls, l, mid, L, R);
        if(mid < R) cover(rs, mid + 1, r, L, R);
        up(now);
    }
    Tree query(int now, int l, int r, int L, int R)
    {
        if(L <= l && r <= R) return tr[now];
        down(now, l, r);
        int mid = (l + r) >> 1;
        if(R <= mid) return query(ls, l, mid, L, R);
        if(mid < L) return query(rs, mid + 1, r, L, R);
        return query(ls, l, mid, L, R) + query(rs, mid + 1, r, L, R);
    }
    inline int max_suf(int now)
    {
        Tree ans = query(1, 1, n, in[hr[now]], in[now]);
        now = fa[hr[now]];
        while(now)
        {
            ans = query(1, 1, n, in[hr[now]], in[now]) + ans;
            now = fa[hr[now]];
        }
        return ans.suf;
    }
} using namespace Seg_Tree;
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    n = reads(), m = reads();
    FOR(i, 2, n)
    {
        int fa = reads();
        Edge_add(fa, i), Edge_add(i, fa);
    }
    dfs1(1), dfs2(1), build(1, 1, n);
    FOR(i, 1, m)
    {
        int ty = reads(), x = reads();
        if(ty == 1) modify(1, 1, n, in[x], 1);
        if(ty == 2)
            cover(1, 1, n, in[x], out[x]),
            modify(1, 1, n, in[x], -max_suf(x) - 1);
        if(ty == 3) puts(max_suf(x) >= 0 ? "black" : "white");
    }
    return 0;
}
posted @ 2022-09-02 09:07  zuytong  阅读(23)  评论(0编辑  收藏  举报