• 【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;
    }
    
    
  • 相关阅读:
    python常用模块
    清除在Windows下访问共享文件夹时的登录信息
    CentOS 6.3下Samba服务器的安装与配置
    textarea定位光标
    js中apply方法的使用
    js call方法
    linux 安装svn,并设置钩子来同步更新
    mysql给root开启远程访问权限,修改root密码
    在VMware的Linux系统上安装Redis
    (转)NoSQL——Redis在win7下安装配置的学习一
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12627103.html
Copyright © 2020-2023  润新知