标签:ace 删除 get 输出 ref 最小 getc struct 假设
参考:Splay详解
1.插入xx数
2.删除xx数(若有多个相同的数,因只删除一个)
3.查询xx数的排名(排名定义为比当前数小的数的个数+1+1。若有多个相同的数,因输出最小的排名)
4.查询排名为xx的数
5.求xx的前驱(前驱定义为小于xx,且最大的数)
6.求xx的后继(后继定义为大于xx,且最小的数)
#include <bits/stdc++.h>
#define inf 1000000005
const int N = 100005;
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[36];int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct node
{
int v;//权值
int fa;//父亲节点
int ch[2];//0代表左儿子,1代表右儿子
int rec;//这个权值的节点出现的次数
int sum;//子节点的数量(包含自己)
}tree[N];//N为节点最多有多少
int tot;//tot表示不算重复的有多少节点
inline void update(register int x)
{
tree[x].sum=tree[tree[x].ch[0]].sum+tree[tree[x].ch[1]].sum+tree[x].rec;
}
inline bool findd(register int x)//这个节点是他父节点的左孩子还是右孩子
{
return tree[tree[x].fa].ch[0]==x?0:1;
}
inline void connect(register int x,register int fa,register int son) //把x转为fa的son(son是0/1,表示左孩子或右孩子)
{
tree[x].fa=fa;
tree[fa].ch[son]=x;
}
inline void rotate(register int x) //以上均为rotate
{
int Y=tree[x].fa;
int R=tree[Y].fa;
int Yson=findd(x);
int Rson=findd(Y);
int B=tree[x].ch[Yson^1];
connect(B,Y,Yson);
connect(Y,x,Yson^1);
connect(x,R,Rson);
update(Y),update(x);
}
inline void splay(register int x,register int to)//把x节点搬到to节点
{
to=tree[to].fa;
while(tree[x].fa!=to)
{
int y=tree[x].fa;
if(tree[y].fa==to)
rotate(x);
else if(findd(x)==findd(y))
rotate(y),rotate(x);
else
rotate(x),rotate(x);
}
}
inline int newpoint(register int v,register int fa)
{
tree[++tot].fa=fa;
tree[tot].v=v;
tree[tot].sum=tree[tot].rec=1;
return tot;
}
inline void Insert(register int x)//插一个值
{
int now=tree[0].ch[1];
if(tree[0].ch[1]==0)
{
newpoint(x,0);
tree[0].ch[1]=tot;
}
else
{
while(19260817)
{
++tree[now].sum;
if(tree[now].v==x)
{
++tree[now].rec;
splay(now,tree[0].ch[1]);
return;
}
int nxt=x<tree[now].v?0:1;
if(!tree[now].ch[nxt])
{
int p=newpoint(x,now);
tree[now].ch[nxt]=p;
splay(p,tree[0].ch[1]);
return;
}
now=tree[now].ch[nxt];
}
}
}
inline int find(register int v)//找位置用find函数
{
int now=tree[0].ch[1];
while(19260817)
{
if(tree[now].v==v)
{
splay(now,tree[0].ch[1]);
return now;
}
int nxt=v<tree[now].v?0:1;
if(!tree[now].ch[nxt])
return 0;
now=tree[now].ch[nxt];
}
}
inline void delet(register int x)//删除权值为v的节点,只删一个
{
int pos=find(x);
if(!pos)
return;
if(tree[pos].rec>1)
{
--tree[pos].rec;
--tree[pos].sum;
}
else
{
if(!tree[pos].ch[0]&&!tree[pos].ch[1])
tree[0].ch[1]=0;
else if(!tree[pos].ch[0])
{
tree[0].ch[1]=tree[pos].ch[1];
tree[tree[0].ch[1]].fa=0;
}
else
{
int left=tree[pos].ch[0];
while(tree[left].ch[1])
left=tree[left].ch[1];
splay(left,tree[pos].ch[0]);
connect(tree[pos].ch[1],left,1);
connect(left,0,1);
update(left);
}
}
}
inline int Rank(register int v)//查询x数的排名
{
int pos=find(v);
return tree[tree[pos].ch[0]].sum+1;
//比当前数小的数的个数+1
//若有多个相同的数,输出最小的排名
}
inline int arank(register int x)//查询排名为x的数
{
int now=tree[0].ch[1];
while(19260817)
{
int used=tree[now].sum-tree[tree[now].ch[1]].sum;
if(x>tree[tree[now].ch[0]].sum&&x<=used)
{
splay(now,tree[0].ch[1]);
return tree[now].v;
}
if(x<used)
now=tree[now].ch[0];
else
x-=used,now=tree[now].ch[1];
}
}
inline int lower(register int v)//前驱
{
int now=tree[0].ch[1];
int ans=-inf;
while(now)
{
if(tree[now].v<v&&tree[now].v>ans)
ans=tree[now].v;
if(v>tree[now].v)
now=tree[now].ch[1];
else
now=tree[now].ch[0];
}
return ans;
}
inline int upper(register int v)//后继
{
int now=tree[0].ch[1];
int ans=inf;
while(now)
{
if(tree[now].v>v&&tree[now].v<ans)
ans=tree[now].v;
if(v<tree[now].v)
now=tree[now].ch[0];
else
now=tree[now].ch[1];
}
return ans;
}
int main()
{
int n;
scanf("%d", &n);
tot = 0;
while(n--){
int op, x;
scanf("%d%d", &op, &x);
if(op == 1) Insert(x);
if(op == 2) delet(x);
if(op == 3) printf("%d\n", Rank(x));
if(op == 4) printf("%d\n", arank(x));
if(op == 5) printf("%d\n", lower(x));
if(op == 6) printf("%d\n", upper(x));
}
return 0;
}
区间操作
假设我们要在[l,r]之间上搞事情,我们首先把l的前驱旋转到根节点,再把r的后继转到根节点的右儿子
那么此时根节点右儿子的左儿子代表的就是区间[l,r]
然后就可以像线段树的lazy标记一样,给区间l,rl,r打上标记,延迟更新,比如区间反转的时候更新的时候直接交换左右儿子
这里有一个奇技淫巧:如果一个区间被打了两次,那么就相当于不打
所以我们用一个bool变量来储存该节点是否需要被旋转
#include <bits/stdc++.h>
#define N 100005
#define inf 0x7fffff
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[36];int cnt=0;
while(x)sta[cnt++]=x%10,x/=10;
while(cnt)putchar(sta[--cnt]+48);
}
int n,m;
struct node{
int fa,ch[2],tot;
bool rev;
}tree[N];
int root,PosL,PosR;
inline bool findd(register int x)
{
return x==tree[tree[x].fa].ch[1];
}
inline void connect(register int x,register int fa,register int son)
{
tree[x].fa=fa;
tree[fa].ch[son]=x;
}
inline void update(register int x)
{
tree[x].tot=tree[tree[x].ch[0]].tot+tree[tree[x].ch[1]].tot+1;
}
inline void rotate(register int x)
{
int Y=tree[x].fa;
if(Y==root)
root=x;
int R=tree[Y].fa;
int Yson=findd(x);
int Rson=findd(Y);
int B=tree[x].ch[Yson^1];
connect(B,Y,Yson);
connect(Y,x,Yson^1);
connect(x,R,Rson);
update(Y);
update(x);
}
inline void splay(register int x,register int to)
{
while(tree[x].fa!=to)
{
int y=tree[x].fa;
if(tree[y].fa==to)
rotate(x);
else if(findd(x)==findd(y))
rotate(y),rotate(x);
else
rotate(x),rotate(x);
}
update(x);
}
inline int buildsplay(register int l,register int r)
{
if(l>r)
return 0;
int mid=l+r>>1;
connect(buildsplay(l,mid-1),mid,0);
connect(buildsplay(mid+1,r),mid,1);
tree[mid].rev=0;
update(mid);
return mid;
}
inline void pushdown(register int x)
{
if(tree[x].rev)
{
swap(tree[x].ch[0],tree[x].ch[1]);
tree[tree[x].ch[0]].rev^=1;
tree[tree[x].ch[1]].rev^=1;
tree[x].rev=0;
}
}
inline int find(register int x)
{
int now=root;
--x;
pushdown(now);
while(x!=tree[tree[now].ch[0]].tot)
{
if(tree[tree[now].ch[0]].tot<x)
x-=tree[tree[now].ch[0]].tot+1,now=tree[now].ch[1];
else
now=tree[now].ch[0];
pushdown(now);
}
return now;
}
inline void print(register int now)
{
if(!now)
return;
pushdown(now);
print(tree[now].ch[0]);
if(now!=1&&now!=n+2)
write(now-1),putchar(' ');
print(tree[now].ch[1]);
}
int main()
{
n=read(),m=read();
root=buildsplay(1,n+2);
while(m--)
{
int l=read(),r=read();
PosL=find(l);
splay(PosL,0);
PosR=find(r+2);
splay(PosR,root);
tree[tree[PosR].ch[0]].rev^=1;
}
print(root);
return 0;
}
标签:ace 删除 get 输出 ref 最小 getc struct 假设
原文地址:https://www.cnblogs.com/KirinSB/p/11669005.html