【洛谷P3261】城池攻占

题目

题目链接:https://www.luogu.com.cn/problem/P3261
臭不要脸的把 LOJ 的题面截图下来

思路

一个显然的思路是从叶子往上跑,将所有可以到点 \(x\) 的骑士扔进一个小根堆里面,然后不停弹出堆顶直到对顶元素的值不小于 \(h[x]\) 或者堆空了。
由于需要堆合并,所以直接上左偏树即可。至于乘和加就在堆顶打 tag,然后合并或弹出的时候再 pushdown 即可。顺序显然是先乘后加。
对于第一问,答案就是在点 \(x\) 被弹出的元素个数;对于第二问,答案是该骑士最先攻击的点的深度减去弹出时点的深度。注意对于攻击完点 \(1\) 依然存活的骑士并不计入 \(1\) 的答案,且不用减去 \(dep[1]\)
时间复杂度 \(O(n\log m)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll N=300010;
ll n,m,tot,head[N],fa[N],a[N],c[N],rt[N],dep[N],ans1[N],ans2[N],h[N],v[N],s[N];

struct edge
{
	ll next,to;
}e[N];

void add(ll from,ll to)
{
	e[++tot]=(edge){head[from],to};
	head[from]=tot;
}

struct LeftistTree
{
	ll val[N],dis[N],lc[N],rc[N],lazy[N][2];
	
	void pushdown(ll x)
	{
		if (lazy[x][1]!=1)
		{
			val[x]*=lazy[x][1];
			lazy[lc[x]][1]*=lazy[x][1]; lazy[rc[x]][1]*=lazy[x][1];
			lazy[lc[x]][0]*=lazy[x][1]; lazy[rc[x]][0]*=lazy[x][1];
		}
		if (lazy[x][0])
		{
			val[x]+=lazy[x][0];
			lazy[lc[x]][0]+=lazy[x][0]; lazy[rc[x]][0]+=lazy[x][0];
		}
		lazy[x][1]=1; lazy[x][0]=0;
	}
	
	ll merge(ll x,ll y)
	{
		if (!x || !y) return x+y;
		pushdown(x); pushdown(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;
	}
}lt;

void dfs(ll x)
{
	dep[x]=dep[fa[x]]+1;
	for (ll i=head[x];~i;i=e[i].next)
	{
		ll v=e[i].to;
		dfs(v);
		rt[x]=lt.merge(rt[x],rt[v]);
	}
	lt.pushdown(rt[x]);
	while (rt[x] && lt.val[rt[x]]<h[x])
	{
		ans1[x]++;
		ans2[rt[x]]=dep[c[rt[x]]]-dep[x];
		rt[x]=lt.merge(lt.lc[rt[x]],lt.rc[rt[x]]);
		lt.pushdown(rt[x]);
	}
	if (a[x]==0) lt.lazy[rt[x]][0]+=v[x];
		else lt.lazy[rt[x]][1]*=v[x],lt.lazy[rt[x]][0]*=v[x];
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%lld%lld",&n,&m);
	for (ll i=1;i<=n;i++)
		scanf("%lld",&h[i]);
	for (ll i=2;i<=n;i++)
	{
		scanf("%lld%lld",&fa[i],&a[i]);
		scanf("%lld",&v[i]);
		add(fa[i],i);
	}
	lt.dis[0]=-1;
	for (ll i=1;i<=m;i++)
	{
		scanf("%lld",&s[i]); scanf("%lld",&c[i]);
		lt.val[i]=s[i]; lt.lazy[i][1]=1;
		rt[c[i]]=lt.merge(rt[c[i]],i);
	}
	dfs(1);
	lt.pushdown(rt[1]);
	while (rt[1])
	{
		ans2[rt[1]]=dep[c[rt[1]]];
		rt[1]=lt.merge(lt.lc[rt[1]],lt.rc[rt[1]]);
		lt.pushdown(rt[1]);
	}
	for (ll i=1;i<=n;i++) printf("%lld\n",ans1[i]);
	for (ll i=1;i<=m;i++) printf("%lld\n",ans2[i]);
	return 0;
}
posted @ 2020-12-01 22:08  stoorz  阅读(74)  评论(0编辑  收藏  举报