线段树套有旋 Treap

部分内容与 Treap\text{Treap} 的相同,这里已省略,重点讲解线段树部分的功能。

另外,代码建树时需要一个辅助数组 bib_i 代表第 ii 个数的初始值。

宏定义

  • #define pl p<<1\texttt{\#define pl p<<1}:线段树中点 pp 的左儿子。
  • #define pr p<<1|1\texttt{\#define pr p<<1|1}:线段树中点 pp 的右儿子。

变量

  • int tot\texttt{int tot}:已使用的节点总数。
  • int nc[i]\texttt{int nc[i]}:预留的第 ii 个内存位。
  • int INF\texttt{int INF}:极大值。
  • struct Tree a[i]\texttt{struct Tree a[i]}:平衡树的节点。
  • struct Treap\texttt{struct Treap}有旋 Treap\text{Treap} 部分。
  • Segmet::struct Tree\texttt{Segmet::struct Tree}:线段树节点结构体。
  • Segmet::struct Tree s[i]\texttt{Segmet::struct Tree s[i]}:线段树节点。
  • int s[i].l\texttt{int s[i].l}:节点 ii 所管理的区间的左端点。
  • int s[i].r\texttt{int s[i].r}:节点 ii 所管理的区间的右端点。
  • Treap s[i].t\texttt{Treap s[i].t}:节点 ii 所管理的区间的平衡树。

函数

  • Segmet::Segmet()\texttt{Segmet::Segmet()}:初始化 Treap\text{Treap}
  • void build(int p,int l,int r)\texttt{void build(int p,int l,int r)}:建树。
  • void change(int p,int x,int lv,int nv)\texttt{void change(int p,int x,int lv,int nv)}:将树中位置为 xx 的值由原来的 lvlv 修改为 rvrv
  • int VtoR(int p,int l,int r,int val)\texttt{int VtoR(int p,int l,int r,int val)}:求 valval 在区间 [l,r][l,r] 内的排名减去 11
  • int RtoV(int l,int r,int rank)\texttt{int RtoV(int l,int r,int rank)}:求区间 [l,r][l,r] 内排名为 rankrank 的数。
  • int pre(int p,int l,int r,int val)\texttt{int pre(int p,int l,int r,int val)}:求 [l,r][l,r] 内值为 valval 的数的前驱,若不存在则返回 INF-INF
  • int nxt(int p,int l,int r,int val)\texttt{int nxt(int p,int l,int r,int val)}:求 [l,r][l,r] 内值为 valval 的数的后继,若不存在则返回 INFINF

代码

int tot,nc[N*20];
int INF=2147483647;
struct Tree{
	int l,r,dat,sz,cnt;
	int val;
}a[N*20];
struct Treap{
	int rt;
	void pushup(int p){
		a[p].sz=a[a[p].l].sz+a[a[p].r].sz+a[p].cnt;
	}
	int get_new(int val){
		int p=nc[++tot];
		a[p].l=a[p].r=0;a[p].dat=rand();
		a[p].sz=a[p].cnt=1;a[p].val=val;
		return p;
	}
	void del(int &p){
		nc[tot--]=p;p=0;
	}
	void build(){
		rt=get_new(-INF);
		a[rt].r=get_new(INF);pushup(rt);
	}
	void zig(int &p){
		int q=a[p].l;
		a[p].l=a[q].r;a[q].r=p;p=q;
		pushup(a[p].r);pushup(p);
	}
	void zag(int &p){
		int q=a[p].r;
		a[p].r=a[q].l;a[q].l=p;p=q;
		pushup(a[p].l);pushup(p);
	}
	void insert(int &p,int val){
		if(!p){
			p=get_new(val);return;
		}
		if(a[p].val==val){
			a[p].cnt++;pushup(p);
			return;
		}
		if(val<a[p].val){
			insert(a[p].l,val);
			if(a[a[p].l].dat>a[p].dat)zig(p);
		}
		else{
			insert(a[p].r,val);
			if(a[a[p].r].dat>a[p].dat)zag(p);
		}
        pushup(p);
	}
	void remove(int &p,int val){
		if(!p)return;
		if(a[p].val==val){
			if(a[p].cnt>1){
				a[p].cnt--;pushup(p);
				return;
			}
			if(a[p].l||a[p].r){
				if(!a[p].r||a[a[p].l].dat>a[a[p].r].dat){
					zig(p);remove(a[p].r,val);
				}
				else{
					zag(p);remove(a[p].l,val);
				}
				pushup(p);return;
			}
			else del(p);
			return;
		}
		if(val<a[p].val)remove(a[p].l,val);
		else remove(a[p].r,val);
		pushup(p);
	}
	int VtoR(int p,int val){
		if(!p)return 0;
		if(val<a[p].val)return VtoR(a[p].l,val);
		if(val==a[p].val)return a[a[p].l].sz;
		return a[a[p].l].sz+a[p].cnt+VtoR(a[p].r,val);
	}
	int pre(int val){
		int ans=1,p=rt;
		while(p){
			if(val==a[p].val){
				if(a[p].l){
					p=a[p].l;
					while(a[p].r)p=a[p].r;
					ans=p;
				}
				break;
			}
			if(a[p].val<val&&a[p].val>a[ans].val)
				ans=p;
			p=(val<a[p].val?a[p].l:a[p].r);
		}
		return a[ans].val;
	}
	int nxt(int val){
		int ans=2,p=rt;
		while(p){
			if(val==a[p].val){
				if(a[p].r){
					p=a[p].r;
					while(a[p].l)p=a[p].l;
					ans=p;
				}
				break;
			}
			if(a[p].val>val&&a[p].val<a[ans].val)
				ans=p;
			p=(val<a[p].val?a[p].l:a[p].r);
		}
		return a[ans].val;
	}
	void dfs(int p){
		if(a[p].l)dfs(a[p].l);
		printf("(%d,%d) ",p,a[p].val);
		if(a[p].r)dfs(a[p].r);
	}
};
#define pl p<<1
#define pr p<<1|1
struct Segmet{
	Segmet(){
		srand(time(0));tot=0;
		for(int i=1;i<N*20;i++)nc[i]=i;
	}
	struct Tree{
		int l,r;
		Treap t;
	}s[N<<2];
	void build(int p,int l,int r){
		s[p].l=l;s[p].r=r;s[p].t.build();
		for(int i=l;i<=r;i++)
			s[p].t.insert(s[p].t.rt,b[i]);
		if(l==r)return;
		int mid=(l+r)>>1;
		build(pl,l,mid);build(pr,mid+1,r);
	}
	void change(int p,int x,int lv,int nv){
		s[p].t.remove(s[p].t.rt,lv);
		s[p].t.insert(s[p].t.rt,nv);
		if(s[p].l==s[p].r)return;
		int mid=(s[p].l+s[p].r)>>1;
		if(x<=mid)change(pl,x,lv,nv);
		else change(pr,x,lv,nv);
	}
	int VtoR(int p,int l,int r,int val){
		if(l<=s[p].l&&s[p].r<=r){
			return s[p].t.VtoR(s[p].t.rt,val)-1;
		}
		int mid=(s[p].l+s[p].r)>>1;
		int ans=0;
		if(l<=mid)ans+=VtoR(pl,l,r,val);
		if(r>mid)ans+=VtoR(pr,l,r,val);
		return ans;
	}
	int RtoV(int l,int r,int rank){
		ll L=0,R=1e8;
		while(L<R){
			ll mid=(L+R+1)>>1;
			if(VtoR(1,l,r,mid)+1<=rank)L=mid;
			else R=mid-1;
		}
		return L;
	}
	int pre(int p,int l,int r,int val){
		if(l<=s[p].l&&s[p].r<=r)
			return s[p].t.pre(val);
		int mid=(s[p].l+s[p].r)>>1;
		int ans=-INF;
		if(l<=mid)ans=max(ans,pre(pl,l,r,val));
		if(r>mid)ans=max(ans,pre(pr,l,r,val));
		return ans;
	}
	int nxt(int p,int l,int r,int val){
		if(l<=s[p].l&&s[p].r<=r)
			return s[p].t.nxt(val);
		int mid=(s[p].l+s[p].r)>>1;
		int ans=INF;
		if(l<=mid)ans=min(ans,nxt(pl,l,r,val));
		if(r>mid)ans=min(ans,nxt(pr,l,r,val));
		return ans;
	}
}tree;
posted @ 2023-08-03 08:32  luckydrawbox  阅读(8)  评论(0)    收藏  举报  来源