题解:
带标记可并堆
用可并堆维护可以到某个城池的士兵
维护小根堆
堆顶小于h时就弹出来计算
注意什么时候下放!!
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const int maxn=300009; typedef long long Lint; int n,m; int s[maxn]; long long h[maxn]; int fa[maxn]={0},ch[maxn][2]={0},dis[maxn]={0}; long long ky[maxn],tag[maxn],mul[maxn]; void Putmul(int x,Lint y){ ky[x]=ky[x]*y; tag[x]=tag[x]*y; mul[x]=mul[x]*y; } void Puttag(int x,Lint y){ ky[x]=ky[x]+y; tag[x]=tag[x]+y; } void pushdown(int x){ if(mul[x]!=1){ if(ch[x][0]){ Putmul(ch[x][0],mul[x]); } if(ch[x][1]){ Putmul(ch[x][1],mul[x]); } mul[x]=1; } if(tag[x]!=0){ if(ch[x][0]){ Puttag(ch[x][0],tag[x]); } if(ch[x][1]){ Puttag(ch[x][1],tag[x]); } tag[x]=0; } } int Getf(int x){ while(fa[x])x=fa[x]; return x; } int Mer(int x,int y){ // pushdown(x);pushdown(y); if((x==0)||(y==0))return x+y; if(ky[x]>ky[y])swap(x,y); pushdown(x);pushdown(y); ch[x][1]=Mer(ch[x][1],y); fa[ch[x][1]]=x; if(dis[ch[x][1]]>dis[ch[x][0]])swap(ch[x][0],ch[x][1]); dis[x]=dis[ch[x][1]]+1; return x; } int rt[maxn]={0}; int cntedge=0; int head[maxn]={0}; int to[maxn<<1],nex[maxn<<1]; void Addedge(int x,int y){ nex[++cntedge]=head[x]; to[cntedge]=y; head[x]=cntedge; } int opty[maxn]; long long v[maxn]; int att[maxn],def[maxn]={0}; int dep[maxn]={0}; void Dp(int x,int father){ dep[x]=dep[father]+1; for(int i=head[x];i;i=nex[i]){ Dp(to[i],x); pushdown(rt[x]);pushdown(rt[to[i]]); rt[x]=Mer(rt[x],rt[to[i]]); } while((rt[x])&&(ky[rt[x]]<h[x])){ int y=rt[x]; att[y]=dep[s[y]]-dep[x]; def[x]++; fa[ch[y][0]]=0; fa[ch[y][1]]=0; pushdown(y); rt[x]=Mer(ch[y][0],ch[y][1]); } if(opty[x]==0){ Puttag(rt[x],v[x]); }else{ Putmul(rt[x],v[x]); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%lld",&h[i]); for(int i=2;i<=n;++i){ int x;scanf("%d",&x);Addedge(x,i); scanf("%d%lld",&opty[i],&v[i]); } for(int i=1;i<=m;++i){ scanf("%lld%d",&ky[i],&s[i]); mul[i]=1; rt[s[i]]=Mer(rt[s[i]],i); } Dp(1,0); while(rt[1]){ int x=rt[1]; att[x]=dep[s[x]]; fa[ch[x][0]]=0; fa[ch[x][1]]=0; rt[1]=Mer(ch[x][0],ch[x][1]); } for(int i=1;i<=n;++i){ printf("%d ",def[i]); } for(int i=1;i<=m;++i){ printf("%d ",att[i]); } return 0; }