对每个城池维护一个骑士的小根堆,如果堆顶元素小于防御值就弹出,对于还在堆中的元素就在堆顶打上这座城池的贡献标记,合并以及pop的时候下传懒标记。父亲合并儿子的堆即可。
注意long long。
Code:
#include<cstdio>
#include<cctype>
#include<algorithm>
#define maxn 300005
#define LL long long
using namespace std;
char cb[1<<15],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &a){
char c;bool f=0;while(!isdigit(c=getc())) if(c=='-') f=1;
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0'); if(f) a=-a;
}
#define lc t[x].l
#define rc t[x].r
struct node{
int l,r,d,id,s,tag;
LL v,add,mul;
inline void mdf(int a,LL b,LL c){
s+=a,tag+=a;
v=v*c+b;
mul*=c,add=add*c+b;
}
}t[maxn];
int n,m,a[maxn],sz,rt[maxn],ans1[maxn],ans2[maxn];
LL h[maxn],V[maxn];
int fir[maxn],nxt[maxn],to[maxn],tot;
inline void line(int x,int y){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;}
inline void upd(int x){
if(t[lc].d<t[rc].d) swap(lc,rc);
t[x].d=t[rc].d+1;
}
inline void pushdown(int x){
if(lc) t[lc].mdf(t[x].tag,t[x].add,t[x].mul);
if(rc) t[rc].mdf(t[x].tag,t[x].add,t[x].mul);
t[x].tag=t[x].add=0,t[x].mul=1;
}
int merge(int x,int y){//
if(!x||!y) return x+y;
if(t[x].v>t[y].v) swap(x,y);
pushdown(x);
rc=merge(rc,y);
upd(x);
return x;
}
int pop(int x){
ans2[t[x].id]=t[x].s;
pushdown(x);
return merge(lc,rc);
}
void dfs(int u){
for(int i=fir[u],v;i;i=nxt[i]){
dfs(v=to[i]);
rt[u]=merge(rt[u],rt[v]);
}
while(rt[u]&&t[rt[u]].v<h[u]) ans1[u]++,rt[u]=pop(rt[u]);
if(rt[u]) t[rt[u]].mdf(1,a[u]?0:V[u],a[u]?V[u]:1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("H.in","r",stdin);
#endif
t[0].d=-1; int x,y;
read(n),read(m);
for(int i=1;i<=n;i++) read(h[i]);
for(int i=2;i<=n;i++) read(x),read(a[i]),read(V[i]),line(x,i);
for(int i=1;i<=m;i++){
read(x),read(y);
t[++sz].id=i,t[sz].v=x,t[sz].mul=1;
rt[y]=merge(rt[y],sz);
}
dfs(1);
while(rt[1]) rt[1]=pop(rt[1]);
for(int i=1;i<=n;i++) printf("%d\n",ans1[i]);
for(int i=1;i<=m;i++) printf("%d\n",ans2[i]);
}