luoguP3261 [JLOI2015]城池攻占
题意
暴力自然是模拟,考虑优化下模拟的过程。
我们对每个点开个左偏树,初始为在该点的骑士,之后dfs过程当中从儿子向父亲合并,同时弹出小于当前点的骑士,增加当前点的答。对于每个骑士的答案,我们记录他的起始点和终点即可。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=300010;
int n,m,cnt;
int head[maxn],def[maxn],type[maxn],delta[maxn],ans1[maxn],ans2[maxn],root[maxn],dep[maxn],st[maxn];
struct edge{int to,nxt;}e[maxn<<1];
struct Heap
{
#define lc(p) (heap[p].lc)
#define rc(p) (heap[p].rc)
#define val(p)(heap[p].val)
#define dis(p) (heap[p].dis)
#define tag1(p) (heap[p].tag1)
#define tag2(p) (heap[p].tag2)
int lc,rc;
int val,dis,tag1,tag2;
}heap[maxn];
inline int read()
{
char c=getchar();int res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
inline void add(int u,int v)
{
e[++cnt].nxt=head[u];
head[u]=cnt;
e[cnt].to=v;
}
inline void move(int x,int mul,int add)
{
if(!x)return;
val(x)*=mul;val(x)+=add;
tag1(x)*=mul;tag2(x)*=mul;tag2(x)+=add;
}
inline void down(int x)
{
move(lc(x),tag1(x),tag2(x)),move(rc(x),tag1(x),tag2(x));
tag1(x)=1,tag2(x)=0;
}
int merge(int x,int y)
{
if(!x||!y)return x+y;
down(x),down(y);
if(val(x)>val(y))swap(x,y);
rc(x)=merge(rc(x),y);
if(dis(rc(x))>dis(lc(x)))swap(lc(x),rc(x));
dis(x)=dis(rc(x))+1;
return x;
}
void dfs(int x,int pre)
{
dep[x]=dep[pre]+1;
for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=pre)dfs(e[i].to,x),root[x]=merge(root[x],root[e[i].to]);
while(root[x]&&val(root[x])<def[x])
{
down(root[x]);
ans1[x]++;ans2[root[x]]=dep[st[root[x]]]-dep[x];
root[x]=merge(lc(root[x]),rc(root[x]));
}
if(type[x])move(root[x],delta[x],0);
else move(root[x],1,delta[x]);
}
signed main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)def[i]=read();
for(int i=2;i<=n;i++)
{
int x=read();add(i,x),add(x,i);
type[i]=read(),delta[i]=read();
}
dis(0)=-1;
for(int i=1;i<=m;i++)tag1(i)=1;
for(int i=1;i<=m;i++)
{
int k=read();st[i]=read();
val(i)=k;
root[st[i]]=merge(root[st[i]],i);
}
dfs(1,0);
while(root[1])down(root[1]),ans2[root[1]]=dep[st[root[1]]],root[1]=merge(lc(root[1]),rc(root[1]));
for(int i=1;i<=n;i++)printf("%lld\n",ans1[i]);
for(int i=1;i<=m;i++)printf("%lld\n",ans2[i]);
return 0;
}