zoukankan      html  css  js  c++  java
  • [JLOI 2015]城池攻占

    Description

    小铭铭最近获得了一副新的桌游,游戏中需要用 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

    第 1 行包含两个正整数 n;m,表示城池的数量和骑士的数量。

    第 2 行包含 n 个整数,其中第 i 个数为 hi,表示城池 i 的防御值。
    第 3 到 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 攻占的城池数量。

    Sample Input

    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

    Sample Output

    2
    2
    0
    0
    0
    1
    1
    3
    1
    1

    HINT

     对于 100% 的数据,1 <= n;m <= 300000; 1 <= fi<i; 1 <= ci <= n; -10^18 <= hi,vi,si <= 10^18;ai等于1或者2;当 ai =1 时,vi > 0;保证任何时候骑士战斗力值的绝对值不超过 10^18。

    题解

    考虑可并堆。

    先将所有 “骑士” 放在 第一个攻占的 “城池” 上。

    将不合法的剔除(即战斗力小于防御力的 “骑士”),统计答案。

    牺牲的骑士数量直接等于 $pop$ 掉的骑士人数,而骑士攻占的城池数等于起始城池与当前城池间的深度差。

    现在考虑修改:可以打上标记, $pushdown$ 时先转移乘法标记,再转移加法标记。转移只需要转移 $merge$ 操作经过的节点。

    值得注意的是,在 $pop$ 堆顶元素时需先将堆顶的标记下移。

     1 //It is made by Awson on 2018.1.4
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime>
     6 #include <queue>
     7 #include <stack>
     8 #include <cstdio>
     9 #include <string>
    10 #include <vector>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define LL long long
    16 #define LD long double
    17 #define Max(a, b) ((a) > (b) ? (a) : (b))
    18 #define Min(a, b) ((a) < (b) ? (a) : (b))
    19 using namespace std;
    20 const int N = 300000;
    21 
    22 struct mergable_tree {
    23     int ch[N+5][2], dist[N+5], root[N+5];
    24     LL prod[N+5], sum[N+5], key[N+5];
    25     mergable_tree() {
    26     for (int i = 1; i <= N; i++) prod[i] = 1;
    27     }
    28     void pushdown(int o) {
    29     #define ls ch[o][0]
    30     #define rs ch[o][1]
    31     if (prod[o] != 1) {
    32         key[ls] *= prod[o], key[rs] *= prod[o]; sum[ls] *= prod[o], sum[rs] *= prod[o]; prod[ls] *= prod[o], prod[rs] *= prod[o];
    33         prod[o] = 1;
    34     }
    35     if (sum[o] != 0) {
    36         key[ls] += sum[o], key[rs] += sum[o]; sum[ls] += sum[o], sum[rs] += sum[o];
    37         sum[o] = 0;
    38     }
    39     #undef ls
    40     #undef rs
    41     }
    42     int merge(int a, int b) {
    43     if (!a || !b) return a+b;
    44     pushdown(a), pushdown(b);
    45     if (key[a] > key[b]) swap(a, b);
    46     ch[a][1] = merge(ch[a][1], b);
    47     if (dist[ch[a][0]] < dist[ch[a][1]]) swap(ch[a][0], ch[a][1]);
    48     dist[a] = dist[ch[a][1]]+1;
    49     return a;
    50     }
    51 }T;
    52 int n, m, f, a[N+5], c[N+5];
    53 LL h[N+5], v[N+5], s;
    54 struct tt {
    55     int to, next;
    56 }edge[N+5];
    57 int path[N+5], top;
    58 int sum[N+5], ans[N+5], dep[N+5];
    59 
    60 void add(int u, int v) {
    61     edge[++top].to = v;
    62     edge[top].next = path[u];
    63     path[u] = top;
    64 }
    65 void dfs(int u, int depth) {
    66     dep[u] = depth;
    67     for (int i = path[u]; i; i = edge[i].next) {
    68     dfs(edge[i].to, depth+1); T.root[u] = T.merge(T.root[u], T.root[edge[i].to]);
    69     }
    70     while (T.key[T.root[u]] < h[u] && T.root[u] != 0) {
    71     ++sum[u];
    72     ans[T.root[u]] = dep[c[T.root[u]]]-depth;
    73     T.pushdown(T.root[u]);
    74     T.root[u] = T.merge(T.ch[T.root[u]][0], T.ch[T.root[u]][1]);
    75     }
    76     if (a[u] == 0) T.key[T.root[u]] += v[u], T.sum[T.root[u]] += v[u];
    77     else T.key[T.root[u]] *= v[u], T.prod[T.root[u]] *= v[u], T.sum[T.root[u]] *= v[u];
    78 }
    79 void work() {
    80     memset(ans, -1, sizeof(ans));
    81     scanf("%d%d", &n, &m);
    82     for (int i = 1; i <= n; i++) scanf("%lld", &h[i]);
    83     for (int i = 2; i <= n; i++) {
    84     scanf("%d%d%lld", &f, &a[i], &v[i]);
    85     add(f, i);
    86     }
    87     for (int i = 1; i <= m; i++) {
    88     scanf("%lld%d", &s, &c[i]);
    89     T.key[i] = s;
    90     T.root[c[i]] = T.merge(T.root[c[i]], i);
    91     }
    92     dfs(1, 1);
    93     for (int i = 1; i <= n; i++) printf("%d
    ", sum[i]);
    94     for (int i = 1; i <= m; i++) printf("%d
    ", ans[i] == -1 ? dep[c[i]] : ans[i]);
    95 }
    96 int main() {
    97     work();
    98     return 0;
    99 }
  • 相关阅读:
    线性代数思维导图——3.向量
    微分中值定理的基础题型总结
    构造函数
    Python课程笔记(七)
    0241. Different Ways to Add Parentheses (M)
    0014. Longest Common Prefix (E)
    0013. Roman to Integer (E)
    0011. Container With Most Water (M)
    0010. Regular Expression Matching (H)
    0012. Integer to Roman (M)
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8194514.html
Copyright © 2011-2022 走看看