萌新求助,关于左偏树的0节点
查看原帖
萌新求助,关于左偏树的0节点
242234
乘湘去楼主2021/3/12 21:47

RT,问题见代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cassert>
#define N 300050
#define LL long long 
using namespace std;

int ans1[N],ans2[N],c[N];
int n,m,fa[N],dep[N],die[N],a[N];
LL def[N],v[N],add[N],mul[N],s[N];

inline int qr()
{
	char a=0;int w=1,x=0;
	while(a<'0'||a>'9'){if(a=='-')w=-1;a=getchar();}
	while(a<='9'&&a>='0'){x=(x<<3)+(x<<1)+(a^48);a=getchar();}
	return x*w;
}

inline LL qrl()
{
	char a=0;LL w=1,x=0;
	while(a<'0'||a>'9'){if(a=='-')w=-1;a=getchar();}
	while(a<='9'&&a>='0'){x=(x<<3)+(x<<1)+(a^48);a=getchar();}
	return x*w;
}

int rt[N],l[N],r[N],dis[N];

inline void spread(int p)//在左偏树上下传标记
{
	if(!add[p]&&mul[p]==1) return ;
	if(l[p])
	{
		mul[l[p]]*=mul[p];
		add[l[p]]*=mul[p];
		add[l[p]]+=add[p];
		s[l[p]]*=mul[p];
		s[l[p]]+=add[p];
	}
	if(r[p])
	{
		mul[r[p]]*=mul[p];
		add[r[p]]*=mul[p];
		add[r[p]]+=add[p];
		s[r[p]]*=mul[p];
		s[r[p]]+=add[p];
	}
	add[p]=0,mul[p]=1;
}

inline int merge(int x,int y)
{
	if(!x||!y) return x|y;
	spread(x); spread(y);
	if(s[x]>s[y]) swap(x,y);
	r[x]=merge(r[x],y);
	if(dis[r[x]]>dis[l[x]]) swap(l[x],r[x]);
	dis[x]=dis[r[x]]+1;
	return x;
}

int main()
{
	n=qr();m=qr();
	for(register int i=1;i<=n;i++) rt[i]=-1;
	for(register int i=1;i<=n;i++) def[i]=qrl();
	dep[1]=1;	
	//**************************************************************//问题在这里
	dis[0]=-1;                            //这里左偏树节点零为负数时就能过 其余几乎全WA 这是为什么?
	//**************************************************************//
	for(register int i=2;i<=n;i++)
	{
		fa[i]=qr();a[i]=qr();v[i]=qrl();
		dep[i]=dep[fa[i]]+1;
	}
	for(register int i=1;i<=m;i++)
	{
		mul[i]=1;
		s[i]=qrl();c[i]=qr();
		if(rt[c[i]]==-1) rt[c[i]]=i;
		else rt[c[i]]=merge(rt[c[i]],i);
	}
	for(register int i=n;i>=1;i--)//从叶子到根遍历树
	{
		while(rt[i]!=-1)//这个节点上有骑士
			if(s[rt[i]]<def[i])//骑士打不过
			{
				die[rt[i]]=i;//骑士挂在这个节点上
				spread(rt[i]);
				if(!l[rt[i]]) rt[i]=-1;//如果这棵树空了,标记一下
				else rt[i]=merge(l[rt[i]],r[rt[i]]);//把根节点删了
			}
			else break;

		if(i==1) break;
		if(rt[i]==-1) continue;
		if(a[i]) mul[rt[i]]*=v[i],add[rt[i]]*=v[i],s[rt[i]]*=v[i];//改变根节点
		else add[rt[i]]+=v[i],s[rt[i]]+=v[i];
		spread(rt[i]);//根节点标记下传
		if(rt[fa[i]]==-1) rt[fa[i]]=rt[i];//如果父节点没东西直接换下根
		else rt[fa[i]]=merge(rt[fa[i]],rt[i]);//有的话合并
	}
	for(register int i=1;i<=m;i++) ans1[die[i]]++;
	for(register int i=1;i<=m;i++) ans2[i]=dep[c[i]]-dep[die[i]];
	for(register int i=1;i<=n;i++) printf("%d\n",ans1[i]);
	for(register int i=1;i<=m;i++) printf("%d\n",ans2[i]);
	return 0;
}
2021/3/12 21:47
加载中...