题目是中文的,也不难理解,懒惰的我就不写大致题意了
题解: DFS + 左偏树(可并堆)
从根1 DFS下去,到一个节点,先处理完他的所有孩子,然后将孩子节点的左偏树和攻击这个节点的骑士的左偏树合并在一起,小根堆,然后判堆顶的值是不是比这个节点的防御值小,是的话就删掉,维护这个节点和堆顶骑士的答案,直到堆空了或者堆顶的值大于这个节点的防御值,对于攻占这个节点后战斗力的变化,打个标记就没问题了
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<vector>
#include<string>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL maxn = 310000;
struct attack
{
LL y,next;
}ak[maxn]; LL alen,firsta[maxn];
void insa( LL x,LL y )
{
alen++;
ak[alen].y = y;
ak[alen].next = firsta[x]; firsta[x] = alen;
}
struct edge
{
LL y,next;
}a[maxn<<1]; LL len,first[maxn];
void insert( LL x,LL y )
{
len++;
a[len].y = y;
a[len].next = first[x]; first[x] = len;
}
struct node
{
LL lc,rc,c,add,mul,dist;
}tr[maxn<<1];
LL n,m;
LL s[maxn],upd[maxn],deadi[maxn];
LL ud[maxn];
LL fa[maxn];
LL at[maxn],dis[maxn],ans[maxn];
void build( LL x,LL f )
{
for( LL k=first[x];k;k=a[k].next )
{
if( a[k].y != f )
{
dis[a[k].y] = dis[x]+1;
build( a[k].y,x );
}
}
}
LL find_( LL x )
{
if( fa[x] == x ) return x;
return fa[x] = find_( fa[x] );
}
void down( LL x )
{
LL lc = tr[x].lc, rc = tr[x].rc;
if( lc )
{
tr[lc].mul *= tr[x].mul;
tr[lc].c *= tr[x].mul;
tr[lc].add *= tr[x].mul;
tr[lc].c += tr[x].add;
tr[lc].add += tr[x].add;
}
if( rc )
{
tr[rc].mul *= tr[x].mul;
tr[rc].c *= tr[x].mul;
tr[rc].add *= tr[x].mul;
tr[rc].c += tr[x].add;
tr[rc].add += tr[x].add;
}
tr[x].add = 0; tr[x].mul = 1;
}
LL merge( LL x,LL y )
{
if( !x ) return y;
if( !y ) return x;
if( tr[x].c > tr[y].c ) swap( x,y );
down( x );
LL k = merge( tr[x].rc,y );
fa[k] = x;
if( tr[tr[x].lc].dist < tr[k].dist ) swap( tr[x].lc,k );
tr[x].rc = k;
tr[x].dist = tr[k].dist+1;
return x;
}
LL dfs( LL x,LL f )
{
LL f1 = 0;
for( LL k=firsta[x];k;k=ak[k].next )
{
LL y = ak[k].y;
if( !f1 ) f1 = find_( ak[k].y );
else f1 = merge( f1,find_( ak[k].y ) );
}
for( LL k=first[x];k;k=a[k].next )
{
if( a[k].y != f )
{
LL tmp = dfs( a[k].y,x );
if( !tmp ) continue;
if( !f1 ) f1 = tmp;
else f1 = merge( f1,find_( tmp ) );
}
}
f1 = find_( f1 );
if( !f1 ) return 0;
down( f1 );
while( tr[f1].c < s[x] )
{
deadi[x]++;
ans[f1] = dis[at[f1]]-dis[x];
down( f1 );
LL tmp = merge( tr[f1].lc,tr[f1].rc );
fa[f1] = tmp; fa[tmp] = tmp;
f1 = tmp;
if( !f1 ) break;
}
if( x == 1 )
{
while( f1 )
{
ans[f1] = dis[at[f1]]+1;
// down( f1 );
LL tmp = merge( tr[f1].lc,tr[f1].rc );
fa[f1] = tmp; fa[tmp] = tmp;
f1 = tmp;
if( !f1 ) break;
}
return 0;
}
if( f1 )
{
if( ud[x] == 0 )
{
tr[f1].c += upd[x];
tr[f1].add += upd[x];
}
else
{
tr[f1].c *= upd[x];
tr[f1].add *= upd[x];
tr[f1].mul *= upd[x];
}
}
return f1;
}
int main()
{
LL x,y,tmp;
scanf("%lld%lld",&n,&m);
for( LL i=1;i<=n;i++ ) scanf("%lld",&s[i]);
for( LL i=2;i<=n;i++ )
{
scanf("%lld%lld%lld",&x,&ud[i],&upd[i]);
insert( i,x ); insert( x,i );
}
for( LL i=1;i<=m;i++ )
{
scanf("%lld%lld",&tr[i].c,&at[i]);
insa( at[i],i );
fa[i] = i;
tr[i].lc = tr[i].rc = 0;
tr[i].add = 0;
tr[i].mul = 1;
}
dis[1] = 0; build( 1,0 );
dfs( 1,0 );
for( LL i=1;i<=n;i++ ) printf("%lld\n",deadi[i]);
for( LL i=1;i<=m;i++ ) printf("%lld\n",ans[i]);
return 0;
}