Luogu P3261 [JLOI2015]城池攻占
dfs时,用可并的小根堆去维护所有活下来的骑士;更新时就直接往外弹即可;然后堆上要维护乘法和加法标记。
#include<iostream>
#include<cstdio>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline ll g() { register ll x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=300010;
int n,m; bool flg[N];
int ls[N],rs[N],d[N],ans1[N],ans2[N];
int vr[N],nxt[N],fir[N],cnt,dep[N],rt[N],st[N];
inline void add(int u,int v)
{vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
ll ad[N],ml[N],h[N],vl[N],tg[N];
inline void cal(int x,ll M,ll A) {
vl[x]=vl[x]*M+A;
ad[x]=ad[x]*M+A,ml[x]*=M;
}
inline void spread(int x) {
if(!ad[x]&&ml[x]==1) return ;
if(ls[x]) cal(ls[x],ml[x],ad[x]);
if(rs[x]) cal(rs[x],ml[x],ad[x]);
ml[x]=1,ad[x]=0;
}
inline int merge(int x,int y) {
if(!x||!y) return x+y;
spread(x),spread(y);
if(vl[x]>vl[y]) swap(x,y);
rs[x]=merge(rs[x],y);
if(d[ls[x]]<d[rs[x]]) swap(ls[x],rs[x]);
d[x]=d[rs[x]]+1; return x;
}
inline void dfs(int u) {
for(R i=fir[u];i;i=nxt[i]) {
R v=vr[i];
dep[v]=dep[u]+1,dfs(v),rt[u]=merge(rt[u],rt[v]);
}
while(rt[u]&&vl[rt[u]]<h[u]) {
spread(rt[u]);
++ans1[u];ans2[rt[u]]=dep[st[rt[u]]]-dep[u];
rt[u]=merge(ls[rt[u]],rs[rt[u]]);
}
if(flg[u]) cal(rt[u],tg[u],0);
else cal(rt[u],1,tg[u]);
}
inline void main() {
n=g(),m=g();
for(R i=1;i<=n;++i) h[i]=g();
for(R i=2,f;i<=n;++i)
f=g(),flg[i]=g(),tg[i]=g(),add(f,i);
for(R i=1;i<=m;++i)
vl[i]=g(),st[i]=g(),
rt[st[i]]=merge(rt[st[i]],i);
dfs(1);
while(rt[1])
spread(rt[1]),
ans2[rt[1]]=dep[st[rt[1]]]+1,
rt[1]=merge(ls[rt[1]],rs[rt[1]]);
for(R i=1;i<=n;++i) printf("%d\n",ans1[i]);
for(R i=1;i<=m;++i) printf("%d\n",ans2[i]);
}
} signed main() {Luitaryi::main(); return 0;}
2020.01.19