zoukankan      html  css  js  c++  java
  • 【洛谷P3835】【模板】可持久化平衡树

    题目

    题目链接:https://www.luogu.com.cn/problem/P3835
    您需要写一种数据结构(可参考题目标题),来维护一个可重整数集合,其中需要提供以下操作( 对于各个以往的历史版本 ):

    1. 插入 (x)
    2. 删除 (x)(若有多个相同的数,应只删除一个,如果没有请忽略该操作
    3. 查询 (x) 的排名(排名定义为比当前数小的数的个数 (+1)
    4. 查询排名为 (x) 的数
    5. (x) 的前驱(前驱定义为小于 (x),且最大的数,如不存在输出 (-2^{31}+1)
    6. (x) 的后继(后继定义为大于 (x),且最小的数,如不存在输出 (2^{31}-1)

    和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
    每个版本的编号即为操作的序号(版本0即为初始状态,空树)
    (nleq 5 imes 10^5,|x|leq 10^9)

    思路

    直接上 FHQ Treap 即可。注意每次 split 和 merge 时都要复制一份节点。
    注意因为 FHQ Treap 是期望深度 (log n) 的,所以节点数量不能开的太死,我开的是 (50) 倍。
    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=500010,MAXN=N*50,Inf=2147483647;
    int n,rt[N];
    
    struct FHQ
    {
    	int tot,ch[MAXN][2],val[MAXN],dat[MAXN],siz[MAXN];
    	
    	void pushup(int x)
    	{
    		siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    	}
    	
    	int New(int v)
    	{
    		int x=++tot;
    		val[x]=v; dat[x]=rand(); siz[x]=1;
    		return x;
    	}
    	
    	int cpynode(int x)
    	{
    		int y=++tot;
    		ch[y][0]=ch[x][0]; ch[y][1]=ch[x][1];
    		val[y]=val[x]; dat[y]=dat[x]; siz[y]=siz[x];
    		return y;
    	}
    	
    	void build()
    	{
    		int x=New(Inf),y=New(-Inf);
    		ch[x][0]=y; pushup(x);
    		rt[0]=x;
    	}
    	
    	void split(int x,int k,int &lc,int &rc)
    	{
    		if (!x) { lc=rc=0; return; }
    		int y=cpynode(x);
    		if (val[y]<=k)
    			lc=y,split(ch[y][1],k,ch[y][1],rc);
    		else
    			rc=y,split(ch[y][0],k,lc,ch[y][0]);
    		pushup(y);
    	}
    	
    	int merge(int x,int y)
    	{
    		if (!x || !y) return x|y;
    		if (dat[x]>dat[y])
    		{
    			int z=cpynode(x);
    			ch[z][1]=merge(ch[z][1],y);
    			pushup(z); return z;
    		}
    		else
    		{
    			int z=cpynode(y);
    			ch[z][0]=merge(x,ch[z][0]);
    			pushup(z); return z;
    		}
    	}
    	
    	void ins(int &root,int v)
    	{
    		int x,y;
    		split(root,v,x,y);
    		root=merge(merge(x,New(v)),y);
    	}
    	
    	void del(int &root,int v)
    	{
    		int x,y,z;
    		split(root,v,x,y); split(x,v-1,x,z);
    		if (val[z]==v) z=merge(ch[z][0],ch[z][1]);
    		root=merge(merge(x,z),y);
    	}
    	
    	int getrk(int &root,int v)
    	{
    		int x,y,z;
    		split(root,v-1,x,y);
    		z=siz[x];
    		root=merge(x,y);
    		return z;
    	}
    	
    	int getval(int x,int k)
    	{
    		if (siz[ch[x][0]]+1==k) return val[x];
    		if (siz[ch[x][0]]>=k) return getval(ch[x][0],k);
    			else return getval(ch[x][1],k-siz[ch[x][0]]-1);
    	}
    	
    	int pre(int &root,int v)
    	{
    		int x,y,z;
    		split(root,v-1,x,y);
    		z=getval(x,siz[x]);
    		root=merge(x,y);
    		return z;
    	}
    	
    	int nxt(int &root,int v)
    	{
    		int x,y,z;
    		split(root,v,x,y);
    		z=getval(y,1);
    		root=merge(x,y);
    		return z;
    	}
    }fhq;
    
    int main()
    {
    	srand(1023);
    	scanf("%d",&n);
    	fhq.build();
    	for (int i=1;i<=n;i++)
    	{
    		int opt,now,x;
    		scanf("%d%d%d",&now,&opt,&x);
    		rt[i]=rt[now];
    		if (opt==1) fhq.ins(rt[i],x);
    		if (opt==2) fhq.del(rt[i],x);
    		if (opt==3) printf("%d
    ",fhq.getrk(rt[i],x));
    		if (opt==4) printf("%d
    ",fhq.getval(rt[i],x+1));
    		if (opt==5) printf("%d
    ",fhq.pre(rt[i],x));
    		if (opt==6) printf("%d
    ",fhq.nxt(rt[i],x));
    	}
    	return 0;
    }
    
  • 相关阅读:
    C#磁吸屏幕窗体类库
    准备
    我写的诗
    How to turn off a laptop keyboard
    How to tell which commit a tag points to in Git?
    Why should I care about lightweight vs. annotated tags?
    How to get rid of “would clobber existing tag”
    Facebook, Google and Twitter threaten to leave Hong Kong over privacy law changes
    The need for legislative reform on secrecy orders
    Can a foreign key be NULL and/or duplicate?
  • 原文地址:https://www.cnblogs.com/stoorz/p/14302112.html
Copyright © 2011-2022 走看看