• 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;
    }
    
  • 相关阅读:
    Ymodem协议(参考STM32)
    嵌入式 Linux 对内存的直接读写(devmem)
    四则运算表达式分解,前中后缀表达式(栈的应用)
    I2C总线的仲裁机制
    用例图【图7】--☆
    顺序图【6】--☆☆
    部署图【图5】--☆
    组件图【图4】--☆
    活动图、泳道【图1】--☆☆
    Mybatis增删改查(CURD)
  • 原文地址:https://www.cnblogs.com/Silymtics/p/15334892.html
Copyright © 2020-2023  润新知