[BZOJ4003]城池攻占

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。

首先我们在每个节点死的是一段子树内的点经各种变化后得到的最小值,为了维护这个过程,我们考虑堆

然后我们发现乘法没有负数,因此两个点同时向上走以后之间的大小关系就不会改变了

因此我们直接在左偏树上打标记即可

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ls ch[x][0]
 6 #define rs ch[x][1]
 7 #define int long long
 8 #define M 300010
 9 using namespace std;
10 int read()
11 {
12     char ch=getchar();int x=0,f=1;
13     while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
14     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
15     return x*f;
16 }
17 int n,m,num;
18 int head[M],rt[M],a[M],v[M],dis[M],val[M],tag1[M],tag2[M],ch[M][2];
19 int fa[M],deep[M],kill[M],dead[M],c[M],h[M];
20 struct point{int to,next;}e[M<<1];
21 void add(int from,int to)
22 {
23     e[++num].next=head[from];
24     e[num].to=to;
25     head[from]=num;
26 }
27 void pushdown(int x,int t1,int t2)
28 {
29     val[x]*=t1,val[x]+=t2;
30     tag1[x]*=t1;tag2[x]*=t1,tag2[x]+=t2;
31 }
32 void push(int x)
33 {
34     pushdown(ls,tag1[x],tag2[x]);
35     pushdown(rs,tag1[x],tag2[x]);
36     tag1[x]=1,tag2[x]=0;
37 }
38 int merge(int x,int y)
39 {
40     if(!x||!y) return x+y;
41     push(x),push(y);
42     if(val[x]>val[y]) swap(x,y);
43     ch[x][1]=merge(rs,y);
44     if(dis[ls]<dis[rs]) swap(ls,rs);
45     dis[x]=dis[rs]+1;
46     return x;
47 }
48 void dfs(int x)
49 {
50     deep[x]=deep[fa[x]]+1;
51     for(int i=head[x];i;i=e[i].next)
52     {
53         int to=e[i].to;dfs(to);
54         rt[x]=merge(rt[x],rt[to]);
55     }
56     while(rt[x]&&val[rt[x]]<h[x])
57     {
58         push(rt[x]);
59         dead[x]++;
60         kill[rt[x]]=deep[c[rt[x]]]-deep[x];
61         rt[x]=merge(ch[rt[x]][0],ch[rt[x]][1]);
62     }
63     if(a[x]) pushdown(rt[x],v[x],0);
64     else pushdown(rt[x],1,v[x]);
65 }
66 #undef int
67 int main()
68 {
69     #define int long long
70     n=read();m=read();
71     for(int i=1;i<=n;i++) h[i]=read();
72     for(int i=2;i<=n;i++)
73     {
74         fa[i]=read(),a[i]=read();
75         v[i]=read(),add(fa[i],i);
76     }
77     for(int i=1;i<=m;i++)
78     {
79         val[i]=read(),c[i]=read();
80         tag1[i]=1,tag2[i]=0;
81         rt[c[i]]=merge(rt[c[i]],i);
82     }
83     dfs(1);
84     while(rt[1])//如果一直没死 
85     {
86         push(rt[1]);
87         kill[rt[1]]=deep[c[rt[1]]];
88         rt[1]=merge(ch[rt[1]][0],ch[rt[1]][1]);
89     }
90     for(int i=1;i<=n;i++) printf("%lld
",dead[i]);
91     for(int i=1;i<=m;i++) printf("%lld
",kill[i]);
92     return 0;
93 }
原文地址:https://www.cnblogs.com/Slrslr/p/10019477.html