蒟蒻splay遇到玄学问题,求解释,悬关
查看原帖
蒟蒻splay遇到玄学问题,求解释,悬关
1518144
Swordmaker楼主2025/6/29 20:21

今天在写splay时,我遇到了一个从未遇到的问题:

以下是错误代码,其中的pushdown函数长这样:

inline void pushdown(int x)
{
  if(tree[x].tag)
  {
    tree[ls(x)].tag^=1,tree[rs(x)].tag^=1;
    swap(ls(x),rs(x));
    tree[x].tag^=1;
  }
}

以下是正确代码,其中的pushdown函数长这样:

inline void pushdown(int x)
{
  if(x&&tree[x].tag)
  {
    tree[ls(x)].tag^=1,tree[rs(x)].tag^=1;
    swap(ls(x),rs(x));
    tree[x].tag^=1;
  }
}

可以发现,两个函数的唯一区别是在pushdown是有没有判断结点为空,但是本蒟蒻找遍了代码,发现似乎并没有哪个地方pushdown下传到了空结点,我也似乎觉得就算访问到空结点也不会对代码造成什么影响吧。

所以为什么会出现这样的情况呢?求Dalao解释。

最后附上ac的完整代码,请Dalao调试

#include<bits/stdc++.h>
#define int long long
//#define getchar getchar_unlocked
//#define putchar putchar_unlocked
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0')
	{
		if(c=='-') f=0;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		x=(x<<3)+(x<<1)+(c^48);
		c=getchar();
	}
	return f?x:-x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
inline void spaceput(int x)
{
	write(x);
	putchar(' ');
}
using namespace std;
constexpr int inf=1e14;
constexpr int N=1e5+5;
int n,tot,idx,root;
struct node
{
	int val,pos;
	friend bool operator < (node A,node B)//重载小于号,保证排序完值相等的元素相对位置大小不变 
	{
		if(A.val!=B.val) return A.val<B.val;
		return A.pos<B.pos;
	}
}a[N];
struct splaytree
{
	int s[2],fa,siz,tag;
}tree[N];
#define fa(x) tree[x].fa
#define ls(x) tree[x].s[0]
#define rs(x) tree[x].s[1]
namespace SplayTree
{
	inline void pushup(int x)
	{
		tree[x].siz=tree[ls(x)].siz+tree[rs(x)].siz+1;
	}
	inline void pushdown(int x)
	{
		if(x&&tree[x].tag)//问题就是在这里
		{
			tree[ls(x)].tag^=1,tree[rs(x)].tag^=1;
			swap(ls(x),rs(x));
			tree[x].tag^=1;
		}
	}
	inline int ident(int x,int f)
	{
		return rs(f)==x;
	}
	inline void connect(int x,int f,int k)
	{
		tree[f].s[k]=x,fa(x)=f;
	}
	void rotate(int x)
	{
		int f=fa(x),ff=fa(f),k=ident(x,f);
		pushdown(x),pushdown(f);
		connect(tree[x].s[k^1],f,k);
		connect(x,ff,ident(f,ff));
		connect(f,x,k^1);
		pushup(f),pushup(x);
	}
	void splay(int x,int top)
	{
		if(!top) root=x;
		while(fa(x)!=top)
		{
			int f=fa(x),ff=fa(f);
			pushdown(ff),pushdown(f),pushdown(x);
			if(ff!=top) ident(x,f)^ident(f,ff)?rotate(x):rotate(f);
			rotate(x);
		}
	}
	int build(int l,int r,int f)
	{
		if(l>r) return 0;
		int mid=(l+r)>>1;
		fa(mid)=f,ls(mid)=build(l,mid-1,mid),rs(mid)=build(mid+1,r,mid),tree[mid].tag=0;
		pushup(mid);
		return mid;
	}
	int findx(int x)
	{
		int now=root;
		while(1)
		{
			pushdown(now);
			if(x<=tree[ls(now)].siz) now=ls(now);
			else
			{
				x-=tree[ls(now)].siz+1;
				if(!x) return now;
				now=rs(now);
			}
		}
	}
	void rev(int x,int y)
	{
		int l=x-1,r=y+1;
		l=findx(l),r=findx(r);
		splay(l,0),splay(r,l);
		tree[ls(rs(root))].tag^=1; 
	}
}
using namespace SplayTree;
signed main()
{
	n=read();
	for(int i=2;i<=n+1;i++)
	{
		a[i].val=read(),a[i].pos=i;
	}
	a[1].val=-inf,a[1].pos=1,a[n+2].val=inf,a[n+2].pos=n+2;
	sort(a+1,a+n+3);
	root=build(1,n+2,0);
	for(int i=2;i<=n+1;i++)
	{
		splay(a[i].pos,0);
		int pos=tree[ls(root)].siz+1;
		spaceput(pos-1);
		rev(i,pos);
	}
	return 0;
}
2025/6/29 20:21
加载中...