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;
    }
    
  • 相关阅读:
    爬虫问题总结
    keras快速开始序贯(Sequential)模型
    参数估计回顾
    CSDN-markdown编辑器 字体颜色修改
    贝叶斯决策学习
    概率论中的基本公式
    VMware tools安装
    Python 常用技巧:库/模块的安装、查看和卸载
    Google 机器学习笔记一 Pandas简介
    支持向量机 数学推导 part3
  • 原文地址:https://www.cnblogs.com/stoorz/p/14302112.html
Copyright © 2011-2022 走看看