LG 题解 CF1017G The Tree

写在前面

一道非常好的树链剖分题。

自己为了做这道题,甚至从中提取出了一道题这个问题貌似很经典

题目传送

Solution

先不考虑第二个操作。

对于第一个操作,把它看做单点加,然后对于每个询问 \(x\),就是要找一个 \(1\)\(x\) 路径上的点 \(i\),使得 \(i\)\(x\) 这段路径的权值和大于 \(i\)\(x\) 之间的距离。

这个操作可以用线段树二分维护。

有另外一个思路就是差分,把所有点的权值初始化为 \(-1\),然后询问就变成了找一个 \(i\),使得 \(i\)\(x\) 这段路径的权值和 \(\ge 0\)

这个信息可以直接维护一个后缀最大值。

考虑 \(2\) 操作,它的本质就是让子树内所有点权变成 \(-1\),但是还不够,因为前面的差分部分还有影响,一个解决办法是在 \(x\) 结点减一个权值 \(v\),不难发现,\(v = Query(x)+1\)

总复杂度 \(O(n \log^2 n)\),细节看代码。

Code

/*
Work by: Suzt_ilymics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 1e5+5;
const int INF = 1e9+7;
const int mod = 1e9+7;

int n, Q;

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

namespace Seg {
    #define lson i << 1
    #define rson i << 1 | 1
    struct Tree {
        int max, sum, lazy, len;
    }tree[MAXN << 2];
    void Push_up(int i) {
        tree[i].max = max(tree[rson].max, tree[rson].sum + tree[lson].max);
        tree[i].sum = tree[lson].sum + tree[rson].sum;
    }
    void Build(int i, int l, int r) {
        tree[i].len = r - l + 1;
        if(l == r) {
            tree[i].max = tree[i].sum = -1;
            return ;
        }
        int mid = (l + r) >> 1;
        Build(lson, l, mid), Build(rson, mid + 1, r);
        Push_up(i);
    }
    void Push_down(int i) {
        if(!tree[i].lazy) return ;
        tree[lson].lazy = -1, tree[rson].lazy = -1;
        tree[lson].sum = -tree[lson].len;
        tree[rson].sum = -tree[rson].len;
        tree[lson].max = -1;
        tree[rson].max = -1;
        tree[i].lazy = 0;
    }
    void Modify(int i, int l, int r, int pos, int val) {
        if(l == r) {
            tree[i].sum += val, tree[i].max += val;
            return ;
        }
        Push_down(i);
        int mid = (l + r) >> 1;
        if(mid >= pos) Modify(lson, l, mid, pos, val);
        else Modify(rson, mid + 1, r, pos, val);
        Push_up(i);
    }
    void Cover(int i, int l, int r, int L, int R) {
        if(L <= l && r <= R) {
            tree[i].sum = -tree[i].len;
            tree[i].max = tree[i].lazy = -1;
            return ;
        }
        Push_down(i);
        int mid = (l + r) >> 1;
        if(mid >= L) Cover(lson, l, mid, L, R);
        if(mid < R) Cover(rson, mid + 1, r, L, R);
        Push_up(i);
    }
    int Query_Sum(int i, int l, int r, int L, int R) {
        if(L <= l && r <= R) return tree[i].sum;
        Push_down(i);
        int mid = (l + r) >> 1, ans = 0;
        if(mid >= L) ans += Query_Sum(lson, l, mid, L, R);
        if(mid < R) ans += Query_Sum(rson, mid + 1, r, L, R);
        return ans;
    }
    int Query_Max(int i, int l, int r, int L, int R) {
        if(L <= l && r <= R) return tree[i].max;
        Push_down(i);
        int mid = (l + r) >> 1, ans = 0;
        bool flag = false;
        if(mid >= L) {
            ans = Query_Max(lson, l, mid, L, R);
            flag = true;
        }
        if(mid < R) {
            int res = Query_Max(rson, mid + 1, r, L, R);
            if(flag) ans = max(ans + Query_Sum(rson, mid + 1, r, L, R), res);
            else ans = res;
        }
        return ans;
    }
}

namespace Cut {
    struct edge { int to, nxt; }e[MAXN << 1];
    int head[MAXN], num_edge = 1;
    int dep[MAXN], fath[MAXN], siz[MAXN], son[MAXN], dfn[MAXN], top[MAXN], cnt = 0;
    void add_edge(int from, int to) { e[++num_edge] = (edge){to, head[from]}, head[from] = num_edge; }
    void dfs(int u, int fa) {
        dep[u] = dep[fa] + 1, fath[u] = fa, siz[u] = 1;
        for(int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if(v == fa) continue;
            dfs(v, u);
            siz[u] += siz[v];
            if(siz[son[u]] < siz[v]) son[u] = v;
        }
    }
    void dfs2(int u, int tp) {
        dfn[u] = ++cnt, top[u] = tp;
        if(son[u]) dfs2(son[u], tp);
        for(int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if(v == fath[u] || v == son[u]) continue;
            dfs2(v, v);
        }
    }
    int Query(int x) {
        int ans = -INF, sum = 0;
        while(top[x] != 1) {
            ans = max(ans, Seg::Query_Max(1, 1, n, dfn[top[x]], dfn[x]) + sum);
            sum += Seg::Query_Sum(1, 1, n, dfn[top[x]], dfn[x]);
            x = fath[top[x]];
        }
        ans = max(ans, Seg::Query_Max(1, 1, n, dfn[1], dfn[x]) + sum);
        return ans;
    }
}

int main()
{
	n = read(), Q = read();
	for(int i = 2, x; i <= n; ++i) x = read(), Cut::add_edge(x, i), Cut::add_edge(i, x);
    Cut::dfs(1, 0), Cut::dfs2(1, 1), Seg::Build(1, 1, n);
    for(int i = 1, opt, x; i <= Q; ++i) {
        opt = read(), x = read();
        if(opt == 1) {
            Seg::Modify(1, 1, n, Cut::dfn[x], 1);
        } else if(opt == 2) {
            Seg::Cover(1, 1, n, Cut::dfn[x], Cut::dfn[x] + Cut::siz[x] - 1);
            Seg::Modify(1, 1, n, Cut::dfn[x], - Cut::Query(x) - 1);
        } else {
            int ans = (Cut::Query(x));
//            printf("%d ", ans);
            puts((ans >= 0) ? "black" : "white");
        }
    }
    return 0;
}
posted @ 2021-09-25 17:16  Suzt_ilymtics  阅读(51)  评论(0编辑  收藏  举报