Splay 模板(国庆作业表)
void update(ll x){sz[x] = sz[son[x][1]] + sz[son[x][0]] + cnt[x];}
// cnt[x] 表示将dt相等的值的个数总和
ll son_type(ll x){return x == son[fa[x]][1];}
void rotate(ll x){
ll y = fa[x], z = fa[y],k = son_type(x);
if(z){son[z][son_type(y)] = x;}
else root = x;fa[x] = z;
son[y][k] = son[x][k^1];
fa[son[y][k]] = y;
son[x][k^1] = y;fa[y] = x;
update(y);update(x);
}
//将x号节点,移到p号点的下面
void splay(ll x,ll p){
for(ll f = fa[x];f = fa[x],f != p;rotate(x))
if(fa[f])rotate(son_type(f)==son_type(x)?f:x);
if(!p)root = x;
}
void insert(ll x){
if(!root){
root = ++tot;
fa[tot] = 0;
sz[tot] = 1;
cnt[tot] = 1;
dt[tot] = x;
return;
}
int pos = getsuc(root,x);
if(dt[pos] == x){splay(pos,0);sz[pos]++;cnt[pos]++;return;}
++tot;ll p = root;
while(!fa[tot])
{
sz[p]++;
if(x<dt[p])
if(son[p][0])p = son[p][0];else son[p][0] = tot,fa[tot] = p;
else if(son[p][1])p = son[p][1];else son[p][1] = tot,fa[tot] = p;
}
dt[tot] = x;cnt[tot] = sz[tot] = 1;
splay(tot,0);
}
求rank操作(+翻转)
void pushdown(int p){
int &ls = son[p][0],&rs = son[p][1];
lzy[ls]^=1;lzy[rs]^=1;
swap(ls,rs);//翻转就是将一个节点的左右儿子交换位置
lzy[p] = 0;
}
int find(int k){
int p=root;
while(p)
{
if(lzy[p])pushdown(p);//此为翻转操作
if(k<=sz[son[p][1]])p=son[p][1];
else if(sz[son[p][1]]+cnt[p]>=k)break;
else{
k-=sz[son[p][1]]+cnt[p];
p=son[p][0];
}
}
splay(p,0);
return p;
}
求后继(前趋同理)
ll getsuc(ll p,ll x){
ll res = 0,ls = son[p][0],rs = son[p][1];
if(x<dt[p]&&ls)res = getsuc(ls,x);
if(res)return res;
if(x<=dt[p])return res = p;
if(rs)res = getsuc(rs,x);
return res;
}
删除操作
void Del(int key)
{
int p=Find(key); //找到要被删除的节点
if(p){
Splay(p); //将待删节点旋转到根
int Ls=Lson[p],Rs=Rson[p];
Father[Ls]=Lson[p]=Rson[p]=Father[Rs]=0; //删除
if(Ls==0){ root=Rs; Father[Rs]=0;} //若p没有左儿子,则右儿子当新的根节点
else{//找左子树中值最大者当新的根节点
root=Ls;
Ls=GetMax(Ls);
Splay(Ls);
Father[Ls]=0;
Father[Rs]=Ls;
Rson[Ls]=Rs;
Size[root]+=Size[Rson[root]]; //注意:别忘了更新根节点的size值
}
}
}