题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=4003
思路
左偏树,每个点建立一个小根堆,每次合并子树的骑士,把能攻占到某个节点的骑士中攻击力小于城池生命的pop掉,最后像线段树/splay一样给root打加/乘标记,注意合理使用long long。
代码
#include <cstdio>
#include <algorithm>
const int maxn=300000;
struct node
{
node* son[2];
node* fa;
int dist,id;
long long val,adv,tmv;
};
node tnode[maxn+10];
node* root[maxn+10];
int n,m,deep[maxn+10],cnt;
int cans[maxn+10],pans[maxn+10],start[maxn+10];
long long live[maxn+10];
inline int puttmv(node* now,long long v)
{
now->val*=v;
now->tmv*=v;
now->adv*=v;
return 0;
}
inline int putadt(node* now,long long v)
{
now->val+=v;
now->adv+=v;
return 0;
}
inline int pushdown(node* now)
{
if(now->son[0]!=NULL)
{
puttmv(now->son[0],now->tmv);
putadt(now->son[0],now->adv);
}
if(now->son[1]!=NULL)
{
puttmv(now->son[1],now->tmv);
putadt(now->son[1],now->adv);
}
now->tmv=1;
now->adv=0;
return 0;
}
inline int upd_dist(node* now)
{
if(now->son[1]!=NULL)
{
now->dist=now->son[1]->dist+1;
}
else
{
now->dist=0;
}
return 0;
}
node* merge(node* a,node* b)
{
if(a==NULL)
{
return b;
}
if(b==NULL)
{
return a;
}
if(a->val>b->val)
{
std::swap(a,b);
}
pushdown(a);
a->son[1]=merge(a->son[1],b);
a->son[1]->fa=a;
if((a->son[0]!=NULL)&&(a->son[1]!=NULL)&&(a->son[0]->dist<a->son[1]->dist))
{
std::swap(a->son[0],a->son[1]);
}
else if((a->son[0]==NULL)&&(a->son[1]!=NULL))
{
a->son[0]=a->son[1];
a->son[1]=NULL;
}
upd_dist(a);
return a;
}
node* getf(node* now)
{
if(now->fa==NULL)
{
return now;
}
return getf(now->fa);
}
inline long long getmax(node* now)
{
return getf(now)->val;
}
inline node* pop(node* now)
{
node* f=getf(now);
pushdown(f);
node* s=merge(f->son[0],f->son[1]);
if(s!=NULL)
{
s->fa=NULL;
}
return s;
}
int pre[maxn+10],now[maxn+10],son[maxn+10],tot,a[maxn+10];
long long v[maxn+10];
inline int ins(int a,int b)
{
pre[++tot]=now[a];
now[a]=tot;
son[tot]=b;
return 0;
}
int dfs(int u)
{
int j=now[u];
while(j)
{
int v=son[j];
deep[v]=deep[u]+1;
dfs(v);
root[u]=merge(root[u],root[v]);
j=pre[j];
}
while((root[u]!=NULL)&&(getmax(root[u])<live[u]))
{
++cans[u];
node* pa=getf(root[u]);
pans[pa->id]=deep[start[pa->id]]-deep[u];
root[u]=pop(root[u]);
}
if(root[u]==NULL)
{
return 0;
}
if(a[u]==0)
{
putadt(root[u],v[u]);
}
else
{
puttmv(root[u],v[u]);
}
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; ++i)
{
scanf("%lld",&live[i]);
}
for(int i=2; i<=n; ++i)
{
int f;
scanf("%d%d%lld",&f,&a[i],&v[i]);
ins(f,i);
}
for(int i=1; i<=m; ++i)
{
int st;
long long att;
scanf("%lld%d",&att,&st);
node* p=&tnode[i];
p->fa=p->son[0]=p->son[1]=NULL;
p->adv=p->dist=0;
p->tmv=1;
p->id=i;
p->val=att;
start[i]=st;
root[st]=merge(root[st],p);
}
deep[1]=1;
dfs(1);
while(root[1]!=NULL)
{
pans[root[1]->id]=deep[start[root[1]->id]];
root[1]=pop(root[1]);
}
for(int i=1; i<=n; ++i)
{
printf("%d\n",cans[i]);
}
for(int i=1; i<=m; ++i)
{
printf("%d\n",pans[i]);
}
return 0;
}