[BZOJ4003][JLOI2015]城池攻占

為{幸葍}努か 提交于 2020-05-04 03:22:59

BZOJ Luogu #sol 补一篇左偏树的题解 骑士对于树上结点挂链,每次合并所有子树上的骑士后把所有攻击力小于城池防御值的骑士弹掉。 左偏树维护加乘懒标记 记得要pushdown delete的时候也要记得pushdown! ##code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const int MAX=300005;
struct edge{int to,next;}a[MAX],b[MAX];
int head[MAX],cnt,ft[MAX];
bool type[MAX];
ll h[MAX],key[MAX],v[MAX],plu[MAX],mul[MAX];
int n,m,ls[MAX],rs[MAX],dis[MAX],str[MAX],dep[MAX],dead[MAX],up[MAX];
ll gi()
{
	ll x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=-1,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*w;
}
void cover(int A,ll c,ll j)
{
	if (!A) return;
	key[A]*=c;key[A]+=j;
	mul[A]*=c;plu[A]*=c;plu[A]+=j;
}
void pushdown(int A)
{
	cover(ls[A],mul[A],plu[A]);
	cover(rs[A],mul[A],plu[A]);
	mul[A]=1;plu[A]=0;
}
int merge(int A,int B)
{
	if (!A||!B) return A+B;
	if (key[A]>key[B]) swap(A,B);
	pushdown(A);pushdown(B);
	rs[A]=merge(rs[A],B);
	if (dis[ls[A]]<dis[rs[A]]) swap(ls[A],rs[A]);
	dis[A]=dis[rs[A]]+1;
	return A;
}
int del(int A)
{
	pushdown(A);
	return merge(ls[A],rs[A]);
}
int dfs(int u,int f)
{
	dep[u]=dep[f]+1;
	int A=0,B;
	for (int e=ft[u];e;e=b[e].next) A=merge(A,b[e].to);
	for (int e=head[u];e;e=a[e].next)
	{
		int v=a[e].to;
		B=dfs(v,u);
		A=merge(A,B);
	}
	while (key[A]<h[u]&&A)
	{
		up[A]=dep[u];++dead[u];
		A=del(A);
	}
	if (type[u]) cover(A,v[u],0);
	else cover(A,1,v[u]);
	return A;
}
int main()
{
	n=gi();m=gi();
	for (int i=1;i<=n;i++) h[i]=gi();
	for (int i=2,u;i<=n;i++)
	{
		u=gi();
		a[++cnt]=(edge){i,head[u]};head[u]=cnt;
		type[i]=gi();v[i]=gi();
	}
	cnt=0;
	for (int i=1;i<=m;i++)
	{
		key[i]=gi();str[i]=gi();
		b[++cnt]=(edge){i,ft[str[i]]};ft[str[i]]=cnt;
	}
	dfs(1,0);
	for (int i=1;i<=n;i++) printf("%d\n",dead[i]);
	for (int j=1;j<=m;j++) printf("%d\n",dep[str[j]]-up[j]);
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!