码迷,mamicode.com
首页 > 其他好文 > 详细

【JLOI 2015】城池攻占

时间:2020-04-03 16:42:24      阅读:62      评论:0      收藏:0      [点我收藏+]

标签:眼睛   dep   lazy   ||   左偏树   amp   namespace   lan   ini   

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\n", res[i]);
    for(int i = 1; i <= m; ++ i) printf("%lld\n", ans[i]);
    return 0;
}

【JLOI 2015】城池攻占

标签:眼睛   dep   lazy   ||   左偏树   amp   namespace   lan   ini   

原文地址:https://www.cnblogs.com/AWhiteWall/p/12627103.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!