JLOI2015 城池攻占
题目链接:戳我
可并堆的一个题目,我写的是左偏树。
我们从下往上面合并,维护一个小根堆,如果在当前节点死亡就弹出,并标记该骑士的终止节点。
这道题和模板不太一样的是还要维护两个标记——add,mul。记得每次调用树上节点值的时候push_down一次!!!
代码如下:
#include<iostream>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define MAXN 300010
using namespace std;
int n,m,tt;
int head[MAXN],rt[MAXN],cnt[MAXN],st[MAXN],en[MAXN],dep[MAXN];
struct knight{int at;long long sum;}kn[MAXN];
struct city{int op,fa;long long val,h;}c[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
struct Node{int ls,rs;long long add,mul,sum,dis;}t[MAXN];
inline void add(int from,int to){edge[++tt].nxt=head[from],edge[tt].to=to,head[from]=tt;}
inline void solve(int x,long long add,long long mul)
{
t[x].sum*=mul;
t[x].sum+=add;
t[x].mul*=mul;
t[x].add*=mul;
t[x].add+=add;
}
inline void push_down(int x)
{
if(t[x].ls) solve(t[x].ls,t[x].add,t[x].mul);
if(t[x].rs) solve(t[x].rs,t[x].add,t[x].mul);
t[x].mul=1,t[x].add=0;
}
inline int merge(int x,int y)
{
if(t[x].sum==-1) x=0;
if(t[y].sum==-1) y=0;
if(x==0||y==0) return x+y;
push_down(x);
push_down(y);
if(t[x].sum>t[y].sum) swap(x,y);
t[x].rs=merge(t[x].rs,y);
if(t[t[x].ls].dis<t[t[x].rs].dis) swap(t[x].ls,t[x].rs);
t[x].dis=t[t[x].rs].dis+1;
return x;
}
inline int pop(int x)
{
t[x].sum=-1;
return merge(t[x].ls,t[x].rs);
}
inline void dfs(int x,int pre)
{
dep[x]=dep[pre]+1;
for(int i=head[x];i;i=edge[i].nxt) dfs(edge[i].to,x);
for(int i=head[x];i;i=edge[i].nxt) rt[x]=merge(rt[x],rt[edge[i].to]);
push_down(rt[x]);
while(rt[x]&&t[rt[x]].sum<c[x].h)
{
push_down(rt[x]);
cnt[x]++;
en[rt[x]]=x;
rt[x]=pop(rt[x]);
}
if(c[x].op==1) solve(rt[x],0,c[x].val);
if(c[x].op==0) solve(rt[x],c[x].val,1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&c[i].h);
for(int i=2;i<=n;i++) scanf("%d%d%lld",&c[i].fa,&c[i].op,&c[i].val),add(c[i].fa,i);
for(int i=1;i<=m;i++) t[i].add=0,t[i].mul=1;
for(int i=1;i<=m;i++)
{
scanf("%lld%d",&kn[i].sum,&kn[i].at);
t[i].sum=kn[i].sum;
st[i]=kn[i].at;
rt[st[i]]=merge(rt[st[i]],i);
}
//for(int i=1;i<=n;i++) printf("%d ",rt[st[i]]); puts("");
dfs(1,0);
for(int i=1;i<=n;i++) printf("%d\n",cnt[i]);
for(int i=1;i<=m;i++) printf("%d\n",dep[st[i]]-dep[en[i]]);
return 0;
}