zoukankan      html  css  js  c++  java
  • 3D 城池攻占 —— 左偏树

    出处:https://www.cnblogs.com/youxam/p/p3261.html

    题目

    小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池。

    这 n 个城池用 1 到 n 的整数表示。除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其中 fi< i。也就是说,所有城池构成了一棵有根树。这 m 个骑士用 1 到 m 的整数表示,其中第 i 个骑士的初始战斗力为 si,第一个攻击的城池为 ci。

    每个城池有一个防御值 hi,如果一个骑士的战斗力大于等于城池的生命值,那么骑士就可以占领这座城池;否则占领失败,骑士将在这座城池牺牲。占领一个城池以后,骑士的战斗力将发生变化,然后继续攻击管辖这座城池的城池,直到占领 1 号城池,或牺牲为止。

    除 1 号城池外,每个城池 i 会给出两个战斗力变化参数 ai,vi。若 ai=0,攻占城池 i 以后骑士战斗力会增加 vi;若 ai=1,攻占城池 i 以后,战斗力会乘以 vi。注意每个骑士是单独计算的。也就是说一个骑士攻击一座城池,不管结果如何,均不会影响其他骑士攻击这座城池的结果。

    现在的问题是,对于每个城池,输出有多少个骑士在这里牺牲;对于每个骑士,输出他攻占的城池数量。

    Input

    第一行包含两个正整数 n,m,表示城池的数量和骑士的数量。
    第二行包含 n 个整数,其中第 i 个数为 hi,表示城池 i 的防御值。
    第三到第 n+1 行,每行包含三个整数。其中第 i+1 行的三个数为 fi,ai,vi,分别表示管辖这座城池的城池编号和两个战斗力变化参数。
    第 n+2 到 n+m+1 行,每行包含两个整数。其中第 n+i 行的两个数为 si,ci,分别表示初始战斗力和第一个攻击的城池。

    Output

    输出 n+m 行,每行包含一个非负整数。其中前 n 行分别表示在城池 1 到 n 牺牲的骑士数量,后 m 行分别表示骑士 1 到 m 攻占的城池数量。

    Example

    样例输入

    5 5
    50 20 10 10 30
    1 1 2
    2 0 5
    2 0 -10
    1 0 10
    20 2
    10 3
    40 4
    20 4
    35 5
    

    样例输出

    2
    2
    0
    0
    0
    1
    1
    3
    1
    1
    

    Hint

    对于 100% 的数据,(1 leq n,m leq 300000, 1 leq f_i 0;保证任何时候骑士战斗力值的绝对值不超过10^{18})

    题解

    解题思路

    在每个节点上建一个堆, 把每个骑士加入进他第一个攻打的城市的堆
    对于每个城市, 将其和子树的堆合并, 然后弹出牺牲的骑士,
    记录牺牲的个数和击败的个数, 对城市的战斗力做相应的操作.
    合并堆用左偏树进行优化

    代码

    #include <cstdio>
    #include <algorithm>
    #define int long long
    using namespace std;
    const int N = 3e5+5;
    int n, m, h[N], d[N], D[N], rt[N], f[N], a[N], v[N], s[N], c[N], t[N], add[N], son[2][N], die[N], ans[N];
    void pd(int x) {
        if (add[x] == 0 && t[x] == 1) return;
        for(int i = 0; i <= 1; i++)
            if (son[i][x]) {
                t[son[i][x]] *= t[x];
                add[son[i][x]] *= t[x];
                add[son[i][x]] += add[x];
                s[son[i][x]] *= t[x];
                s[son[i][x]] += add[x];
            }
        add[x] = 0; t[x] = 1;
    }
    int merge(int x, int y) {
        if (!x || !y) return x ^ y;
        pd(x); pd(y);
        if (s[x] > s[y]) swap(x, y);
        son[1][x] = merge(son[1][x], y);
        if (d[son[0][x]] < d[son[1][x]])
            swap(son[0][x], son[1][x]);
        d[x] = d[son[0][x]] + 1;
        return x;
    }
    signed main() {
        // freopen("1.in", "r", stdin);
        scanf("%lld%lld", &n, &m);
        for(int i = 1; i <= n; i++)
            scanf("%lld", &h[i]), rt[i] = -1;
        D[1] = 1; d[0] = -1;
        for(int i = 2; i <= n; i++) {
            scanf("%lld%lld%lld", &f[i], &a[i], &v[i]);
            D[i] = D[f[i]] + 1;
        }
        for(int i = 1; i <= m; i++) {
            scanf("%lld%lld", &s[i], &c[i]);
            t[i] = 1;
            if (rt[c[i]] == -1) rt[c[i]] = i;
            else rt[c[i]] = merge(rt[c[i]], i);
        }
        for(int i = n; i > 0; i--) {
            while (rt[i] != -1) {
                if (s[rt[i]] < h[i]) {
                    die[rt[i]] = i;
                    pd(rt[i]);
                    if (!son[0][rt[i]]) rt[i] = -1;
                    else rt[i] = merge(son[0][rt[i]], son[1][rt[i]]);
                }
                else break;
            }
            if (i == 1) break;
            if (rt[i] == -1) continue;
            if (a[i]) {
                t[rt[i]] *= v[i];
                add[rt[i]] *= v[i];
                s[rt[i]] *= v[i];
            }
            else add[rt[i]] += v[i], s[rt[i]] += v[i];
            pd(rt[i]);
            if (rt[f[i]] == -1) rt[f[i]] = rt[i];
            else rt[f[i]] = merge(rt[f[i]], rt[i]);
        }
        for(int i = 1; i <= m; i++) 
            ans[die[i]]++;
        for(int i = 1; i <= n; i++)
            printf("%lld
    ", ans[i]);
        for(int i = 1; i <= m; i++) 
            printf("%lld
    ", D[c[i]] - D[die[i]]);
        return 0;
    }
    
  • 相关阅读:
    1014 Waiting in Line (30)(30 point(s))
    1013 Battle Over Cities (25)(25 point(s))
    1012 The Best Rank (25)(25 point(s))
    1011 World Cup Betting (20)(20 point(s))
    1010 Radix (25)(25 point(s))
    1009 Product of Polynomials (25)(25 point(s))
    1008 Elevator (20)(20 point(s))
    1007 Maximum Subsequence Sum (25)(25 point(s))
    1006 Sign In and Sign Out (25)(25 point(s))
    1005 Spell It Right (20)(20 point(s))
  • 原文地址:https://www.cnblogs.com/shawk/p/12930329.html
Copyright © 2011-2022 走看看