左偏树 (p3261) 对我来说是一道进阶题

题意:有n座城池,m个人;

每座城池有一个耐久度;

每座城池有一个父亲城池(肯定会形成一棵树),还有flag base (这个看题意)

每个人有一个战力值和一个开始进攻的城池序号;

问:1.每个城池能够使将领死亡的死亡数 2.每个将领能够攻占的城池数量; 

思路,这道题是一颗树,所以自然而然的想到用dfs传到根节点,再传回去这种做法;

那么在这种做法下,我们建立最小堆,对每一个节点建立一个最小堆,然后遍历的时候,将小于limit[]的将领弹出;

这个时候需要更新答案, 这个城池的将领死亡数量+1;这个将领攻占的城池数量;

然后   剩下的将领有一个val需要更新 这个时候我们不是直接更新,而是用一个懒惰节点去降低复杂度;

一步一步传给子节点更新;

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<math.h>
 4 #include<string.h>
 5 using namespace std;
 6 typedef long long ll;
 7 const ll maxn=3e5+10;
 8 ll flag[maxn],base[maxn];      //城池的val更新方式
 9 ll ch[maxn][2];   //子节点
10 ll val[maxn],guishu[maxn];  //将领的战力值和第一个城池
11 ll root[maxn];   //每一个城池的根节点;
12 ll dep[maxn],dis[maxn];  //dep是用来计算将领的攻占城池数量的, dis是左偏树的深度;
13 ll ans1[maxn],ans2[maxn]; //城池答案,将领答案;
14 ll mul[maxn],add[maxn];  //懒惰标记
15 ll limit[maxn]; //城池耐久值
16 struct node  //邻接表
17 {
18     ll v,next;
19 }G[maxn]; ll head[maxn];ll num=-1;
20 void build(ll u,ll v)   
21 {
22     G[++num].v=v;G[num].next=head[u];head[u]=num;
23 }
24 void cov(ll x,ll c,ll j)
25 {
26     if(!x) return;
27     val[x]*=c;val[x]+=j;  //这里有一个乘和一个加,自然是先乘后加; 这是根据下文这两句来确定的
28     mul[x]*=c;   //这里的确定方式是将已经有的懒惰节点的值与本次加进来的懒惰节点更新;
29                  //已经有的,自然那些要+的,也要乘上这次的数,然后再加上这次要加的数
30                 //注:下次看这里看不懂的话,多看一下肯定会懂的
31     add[x]*=c;add[x]+=j;
32 }
33 void pushdown(ll x)
34 {  //左右儿子都得更新
35     cov(ch[x][0],mul[x],add[x]);
36     cov(ch[x][1],mul[x],add[x]);
37     mul[x]=1;add[x]=0;
38 }
39 ll Merge(ll x,ll y)
40 {
41     if(!x||!y) return x+y;
42     pushdown(x);pushdown(y);
43     if(val[x]>val[y]) swap(x,y);
44     ch[x][1]=Merge(ch[x][1],y);
45     if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
46     dis[x]=dis[ch[x][1]]+1;
47     return x;
48 }
49 
50 void dfs(ll u,ll fa)
51 {
52     dep[u]=dep[fa]+1;
53     for(ll i=head[u];i!=-1;i=G[i].next){
54         ll v=G[i].v;
55         dfs(v,u);
56         root[u]=Merge(root[u],root[v]);
57     }
58     while(root[u]&&val[root[u]]<limit[u]){
59         pushdown(root[u]);   
60         ans1[u]++;
61         ans2[root[u]]=dep[guishu[root[u]]]-dep[u];
62         ll t=root[u];
63         root[u]=Merge(ch[t][0],ch[t][1]);
64     }
65     if(flag[u]) cov(root[u],base[u],0);
66     else        cov(root[u],1,base[u]);
67 }
68 int main()
69 {
70     ll n,m;
71     memset(head,-1,sizeof(head));
72     scanf("%lld%lld",&n,&m);
73     for(ll i=1;i<=n;i++) scanf("%lld",&limit[i]);
74     for(ll i=2;i<=n;i++){
75         ll u;
76         scanf("%lld%lld%lld",&u,&flag[i],&base[i]);
77         build(u,i);
78     }
79     for(ll i=1;i<=m;i++){
80         scanf("%lld%lld",&val[i],&guishu[i]);
81         ll t=guishu[i];
82         mul[i]=1;
83         if(!root[t]) root[t]=i;
84         else root[t]=Merge(root[t],i);
85     }
86     dfs(1,0);
87     while(root[1]){
88         pushdown(root[1]);
89         ans2[root[1]]=dep[guishu[root[1]]];
90         root[1]=Merge(ch[root[1]][0],ch[root[1]][1]);
91     }
92     for(ll i=1;i<=n;i++) printf("%lld\n",ans1[i]);
93     for(ll i=1;i<=n;i++) printf("%lld\n",ans2[i]);
94     return 0;
95 }

 

posted @ 2019-10-25 20:33  古比  阅读(168)  评论(0编辑  收藏  举报