zoukankan      html  css  js  c++  java
  • 【JLOI 2015】城池攻占

    Solution

    现在感觉自己的眼睛要瞎了。

    我们发现这东西好像挺适合左偏树的啊:骑士在儿子节点死了就不会走到父亲节点,可以直接删去。

    考虑到这条性质(而且城池本来就是树),我们在每个城池建一颗关于骑士的树,表示这一坨骑士都可以来到这个城池。

    我们把最小值作为骑士的根,那么就可以删根然后统计城池的死亡骑士和骑士到哪座城池。

    关于战斗力,我们把骑士树进行一个 lazy 标记就行了,因为我们是从根开始删除的。

    注意要考虑挺到最后的骑士。

    Code

    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    const int N = 3e5 + 5;
    
    int n, m, head[N], dot[N << 1], nxt[N << 1], cnt;
    ll ans[N], res[N];
    
    void addEdge(const int u, const int v) {
        dot[++ cnt] = v; nxt[cnt] = head[u]; head[u] = cnt;
    }
    
    ll read() {
        ll x = 0, f = 1; char s;
        while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
        while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
        return x * f;
    }
    
    struct LT {
        int f[N], son[N][2], dis[N], b[N], dep[N], a[N];
        ll val[N], mul[N], add[N], h[N], Val[N];
    
        void sign(const int o, const ll Mul, const ll Add) {
            if(! o) return;
            val[o] *= Mul; val[o] += Add;
            mul[o] *= Mul; add[o] *= Mul; add[o] += Add;
        }
    
        void pushDown(const int o) {
            sign(son[o][0], mul[o], add[o]);
            sign(son[o][1], mul[o], add[o]);
            mul[o] = 1, add[o] = 0;
        }
    
        int unite(int x, int y) {
            if(! x || ! y) return x | y;
            pushDown(x), pushDown(y);
            if(val[x] > val[y]) swap(x, y);
            son[x][1] = unite(son[x][1], y);
            if(dis[son[x][0]] < dis[son[x][1]]) swap(son[x][0], son[x][1]);
            dis[x] = dis[son[x][1]] + 1;
            return x;
        }
    
        void init() {
            dep[1] = 1;
            for(int i = 1; i <= n; ++ i) {
                son[i][0] = son[i][1] = dis[i] = 0;
            }
            int x;
            for(int i = 1; i <= n; ++ i) h[i] = read();
            for(int i = 2; i <= n; ++ i) {
                x = read(), a[i] = read(), Val[i] = read();
                addEdge(x, i);
            }
            for(int i = 1; i <= m; ++ i) {
                val[i] = read(), b[i] = read();
                mul[i] = 1;
                f[b[i]] = unite(f[b[i]], i);
            }
        }
    
        int del(const int x) {
            int l = son[x][0], r = son[x][1];
            return unite(l, r);
        }
    
        void solve(const int u) {
            for(int i = head[u]; i; i = nxt[i]) {
                int v = dot[i];
                dep[v] = dep[u] + 1; solve(v);
                f[u] = unite(f[u], f[v]);
            }
            while(f[u] && val[f[u]] < h[u]) {
                pushDown(f[u]);
                ++ res[u]; ans[f[u]] = dep[b[f[u]]] - dep[u];
                f[u] = del(f[u]);
            }
            if(a[u]) sign(f[u], Val[u], 0);
            else sign(f[u], 1, Val[u]);
        }
    }T;
    
    int main() {
        n = read(), m = read();
        T.init(); T.solve(1);
        while(T.f[1]) {
            T.pushDown(T.f[1]);
            ans[T.f[1]] = T.dep[T.b[T.f[1]]];
            T.f[1] = T.del(T.f[1]);
        }
        for(int i = 1; i <= n; ++ i) printf("%lld
    ", res[i]);
        for(int i = 1; i <= m; ++ i) printf("%lld
    ", ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    LeetCode 1122. Relative Sort Array (数组的相对排序)
    LeetCode 46. Permutations (全排列)
    LeetCode 47. Permutations II (全排列 II)
    LeetCode 77. Combinations (组合)
    LeetCode 1005. Maximize Sum Of Array After K Negations (K 次取反后最大化的数组和)
    LeetCode 922. Sort Array By Parity II (按奇偶排序数组 II)
    LeetCode 1219. Path with Maximum Gold (黄金矿工)
    LeetCode 1029. Two City Scheduling (两地调度)
    LeetCode 392. Is Subsequence (判断子序列)
    写程序判断系统是大端序还是小端序
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12627103.html
Copyright © 2011-2022 走看看