今天在写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;
}