方法: 可并堆
解析:
今年的省选题,当时我做的时候一顿蒙B。
好像当时搞了个树形DP?不记得了,反正没拿到分。
这题首先->骑士之间互不影响
->到一个城池后所有到达的骑士都要改变攻击力
->并且每次到一个城池把小于该城池防御力的骑士杀死。
这一想..维护一个小根堆….最后一直传到根节点,然后再把根节点连一个防御力正无穷的城池不就好了么。
每次到一个节点后把这个堆里小于他防御力的骑士干死。
然后合并一个节点所有子节点时涉及到合并操作。
所以考虑到可并堆。
然后我们从顶向下递归搞是不行的,要爆栈,所以保险起见我们从下向上搜。
但是直接搜不行,因为在处理一个节点前要处理它的所有子节点。
所以在拓扑图上搞就可以了。
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 300010
#define INF (1ll<<63)-1
using namespace std;
typedef long long ll;
int n,m,cnt,cnt_l,top;
ll h[N],v[N],val[N];
int a[N],head[N],head_l[N],fa[N],du[N];
int he[N],ch[N][2],att[N],col[N],kill[N];
ll siz[N];
ll add[N],mul[N];
int stk[N],fron[N];
char getc()
{
static const int LEN=1<<15;
static char buf[LEN],*S=buf,*T=buf;
if(S==T)
{
T=(S=buf)+fread(buf,1,LEN,stdin);
if(S==T) return EOF;
}
return *S++;
}
int read()
{
static char ch;
static int D;
while(!isdigit(ch=getc()));
for(D=ch-'0';isdigit(ch=getc());)
D=(D<<3)+(D<<1)+(ch-'0');
return D;
}
ll readll()
{
static char ch;
static ll D;
ll f=1;
while(!isdigit(ch=getc())){if(ch=='-')f=-1;}
for(D=ch-'0';isdigit(ch=getc());)
D=(D<<3)+(D<<1)+(ch-'0');
return D*f;
}
struct node
{
int from,to,next;
}edge[N];
struct link
{
int from,to,next;
}l[N];
int find(int x)
{
while(fa[x])x=fa[x];
return x;
}
void init()
{
he[0]=-1;
memset(head,-1,sizeof(head));
memset(head_l,-1,sizeof(head_l));
for(int i=1;i<=m;i++)mul[i]=1;
cnt=1,cnt_l=1;
}
void edgeadd(int from,int to)
{
edge[cnt].from=from,edge[cnt].to=to,edge[cnt].next=head[from];
head[from]=cnt++;
}
void linkadd(int from,int to)
{
l[cnt_l].from=from,l[cnt_l].to=to,l[cnt_l].next=head_l[from];
head_l[from]=cnt_l++;
}
void pushup(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void pushdown(int x)
{
if(add[x]!=0||mul[x]!=1)
{
if(ch[x][0]!=0)
{
val[ch[x][0]]*=mul[x];
val[ch[x][0]]+=add[x];
add[ch[x][0]]*=mul[x];
add[ch[x][0]]+=add[x];
mul[ch[x][0]]*=mul[x];
}
if(ch[x][1]!=0)
{
val[ch[x][1]]*=mul[x];
val[ch[x][1]]+=add[x];
add[ch[x][1]]*=mul[x];
add[ch[x][1]]+=add[x];
mul[ch[x][1]]*=mul[x];
}
add[x]=0,mul[x]=1;
}
}
void pushdown_att(int x)
{
if(col[x])
{
if(ch[x][0]!=0)
col[ch[x][0]]+=col[x],att[ch[x][0]]+=col[x];
if(ch[x][1]!=0)
col[ch[x][1]]+=col[x],att[ch[x][1]]+=col[x];
col[x]=0;
}
}
int merge(int x,int y)
{
if((!x)||(!y))return x+y;
if(val[y]<val[x])swap(x,y);
pushdown(x),pushdown_att(x);
ch[x][1]=merge(ch[x][1],y);
fa[ch[x][1]]=x;
if(he[ch[x][1]]>he[ch[x][0]])swap(ch[x][0],ch[x][1]);
he[x]=he[ch[x][1]]+1;
pushup(x);
return x;
}
struct ele
{
int x,pre;
};
void bfs()
{
for(int i=1;i<=n;i++)
{
if(du[i]==0)
{
stk[++top]=i;
}
}
while(top)
{
int u=stk[top--];
int pre=0;
for(int i=head_l[u];i!=-1;i=l[i].next)
{
int to=l[i].to;
int t=merge(pre,to);
pre=t;
}
int t=merge(pre,fron[u]);
fron[u]=t;
while(val[fron[u]]<h[u]&&fron[u])
{
pushdown(fron[u]),pushdown_att(fron[u]);
int t=merge(ch[fron[u]][0],ch[fron[u]][1]);
fa[t]=0;
fa[fron[u]]=ch[fron[u]][0]=ch[fron[u]][1]=0;
kill[u]++;
fron[u]=t;
}
col[fron[u]]++,att[fron[u]]++;
if(!a[u])
{
val[fron[u]]+=v[u];
add[fron[u]]+=v[u];
}else
{
val[fron[u]]*=v[u];
mul[fron[u]]*=v[u];
add[fron[u]]*=v[u];
}
for(int i=head[u];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
fron[to]=merge(fron[to],fron[u]);
du[to]--;
if(!du[to])stk[++top]=to;
}
}
}
int main()
{
n=read(),m=read();
init();
for(int i=1;i<=n;i++)h[i]=readll();
h[n+1]=INF,edgeadd(1,1+n);
du[1+n]=1;
for(int i=2;i<=n;i++)
{
int pre;
pre=read(),a[i]=read(),v[i]=readll();
edgeadd(i,pre);
du[pre]++;
}
for(int i=1;i<=m;i++)
{
int fir;
val[i]=readll(),fir=read();
linkadd(fir,i);
}
bfs();
for(int i=1;i<=n;i++)printf("%d\n",kill[i]);
for(int i=1;i<=m;i++)printf("%d\n",att[i]);
}