一道yy好题。
qwq首先根据题意,不难发现,我们要对于每个点维护一个小根堆,然后每次对于每一个点来说,如果当前的堆顶的骑士的攻击力小于城池的生命值,那就弹出栈。
但是对于修改操作,我们应该怎么做呢?
其实可以直接像线段树那样,类似打标记的方式去做,但是记得要多 p u s h d o w n pushdown pushdown几次来避免一些玄学错误。
nline void pushdown(int x)
{
if (!x) return;
if (cheng[x]!=1)
{
cheng[ch[x][0]]*=cheng[x];
cheng[ch[x][1]]*=cheng[x];
add[ch[x][0]]*=cheng[x];
add[ch[x][1]]*=cheng[x];
val[ch[x][0]]*=cheng[x];
val[ch[x][1]]*=cheng[x];
cheng[x]=1;
}
if (add[x])
{
add[ch[x][0]]+=add[x];
add[ch[x][1]]+=add[x];
val[ch[x][0]]+=add[x];
val[ch[x][1]]+=add[x];
add[x]=0;
}
}
int merge(int x,int y)
{
pushdown(x);
pushdown(y);
if (x==0 || y==0) return x+y;
if (val[x]>val[y]) swap(x,y);
ch[x][1]=merge(ch[x][1],y);
fa[ch[x][1]]=x;
if (dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
dis[x]=dis[ch[x][1]]+1;
return x;
}
int pop(int x,int dep)
{
pushdown(x);
fa[x]=0;
val[x]=0;
endd[x]=dep;
fa[ch[x][0]]=ch[x][0];
fa[ch[x][1]]=ch[x][1];
return merge(ch[x][0],ch[x][1]);
}
那么对于题目要求的每个骑士的初始的城堡,我们可以通过一个 v e c t o r vector vector来合并,对于一个节点来说,先合并好在这个节点开始的那些骑士,然后再去合并他的儿子。
感觉还是有很多细节的(比如说打乘法标记的时候要记得把对应节点的加法标记也乘上对应的值。
直接上代码
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
#define rint register int
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 4e5+1e2;
const int maxm = 2*maxn;
int ch[maxn][2];
ll add[maxn],cheng[maxn];
int root[maxn];
int fa[maxn],dis[maxn];
ll h[maxn];
int a[maxn];
ll v[maxn];
ll val[maxn];
int c[maxn];
int deep[maxn];
vector<int> vec[maxn];
int point[maxn],nxt[maxm],to[maxm];
int cnt,n,m;
int ans[maxn];
int endd[maxn];
inline void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
int find(int x)
{
if (fa[x]!=x) return find(fa[x]);
return fa[x];
}
inline void pushdown(int x)
{
if (!x) return;
if (cheng[x]!=1)
{
cheng[ch[x][0]]*=cheng[x];
cheng[ch[x][1]]*=cheng[x];
add[ch[x][0]]*=cheng[x];
add[ch[x][1]]*=cheng[x];
val[ch[x][0]]*=cheng[x];
val[ch[x][1]]*=cheng[x];
cheng[x]=1;
}
if (add[x])
{
add[ch[x][0]]+=add[x];
add[ch[x][1]]+=add[x];
val[ch[x][0]]+=add[x];
val[ch[x][1]]+=add[x];
add[x]=0;
}
}
int merge(int x,int y)
{
pushdown(x);
pushdown(y);
if (x==0 || y==0) return x+y;
if (val[x]>val[y]) swap(x,y);
ch[x][1]=merge(ch[x][1],y);
fa[ch[x][1]]=x;
if (dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
dis[x]=dis[ch[x][1]]+1;
return x;
}
int pop(int x,int dep)
{
pushdown(x);
fa[x]=0;
val[x]=0;
endd[x]=dep;
fa[ch[x][0]]=ch[x][0];
fa[ch[x][1]]=ch[x][1];
return merge(ch[x][0],ch[x][1]);
}
void solve(int x,int fa,int dep)
{
deep[x]=dep;
for (rint i=point[x];i;i=nxt[i])
{
int p=to[i];
if (p==fa) continue;
solve(p,x,dep+1);
}
}
void dfs(int x,int fa)
{
int now = 0;
for (rint i=0;i<vec[x].size();++i) now = merge(now,vec[x][i]);
for (rint i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==fa) continue;
dfs(p,x);
now = merge(now,root[p]);
}
int num=0;
while (val[now]<h[x] && now!=0)
{
now = pop(now,deep[x]);
num++;
}
root[x]=now;
ans[x]=num;
if (a[x]==1)
{
cheng[now]*=v[x];
add[now]*=v[x];
val[now]*=v[x];
}
else
{
add[now]+=v[x];
val[now]+=v[x];
}
//cout<<x<<" "<<num<<" "<<root[x]<<" "<<val[now]<<endl;
}
void print(ll x)
{
if (x>=10) print(x/10);
putchar(x%10+'0');
}
signed main()
{
n=read(),m=read();
for (rint i=1;i<=n;++i) h[i]=read();
for (rint i=1;i<=m;++i) fa[i]=i,add[i]=0,cheng[i]=1;
for (rint i=2;i<=n;++i)
{
int x=read();
a[i]=read(),v[i]=read();
addedge(x,i);
addedge(i,x);
}
for (rint i=1;i<=m;++i)
{
val[i]=read();
c[i]=read();
vec[c[i]].pb(i);
}
solve(1,0,1);
dfs(1,0);
for (rint i=1;i<=n;++i)
{
cout<<ans[i]<<"\n";
}
for (rint i=1;i<=m;++i)
{
cout<<deep[c[i]]-endd[i]<<"\n";
}
return 0;
}