• 二逼平衡树(线段树套平衡树)


    线段树套平衡树
    【题目】
    先引入模板题:二逼平衡树
    本题要求实现一个数据结构,可以查询:
    区间内x的排名/前驱/后继,排名为k的数;支持单点修改。
    【思考】
    来源:二逼平衡树-线段树套无旋Treap
    看到排名,可以联想到平衡树,但平衡树并不能直接实现区间操作。
    看到区间修改,可以联想到线段树。
    我们就把两个数据结构放在一起:
    外层线段树,内层平衡树。
    具体来说,在线段树的每个节点上(对每个区间)开一颗平衡树。
    【操作】
    1.前驱后继,在区间内找到最大/最小。
    2.求排名,在区间内统计\(<x\)的数的个数,全部加起来再+1。
    3.单点修改,在所有含\(x\)的平衡树上,暴力删数并插入。
    4.排名为\(k\)的树,二分答案,查询排名是否符合。
    怎么保证找到的在序列中呢?一个数及更大的数(\(<\)序列中比它大的第一个数)查询到的排名相同,与其他都不同,所以最小符合条件的肯定是要查询的,且在序列中。
    网上鲜有用无旋treap的,大多用splay。
    无旋treap好写,为什么不用呢?

    #include <bits/stdc++.h>
    using namespace std;
    struct treap {
        int val[100005],size[100005],son[100005][2],rt,tot,key[100005];
        void update(int a) {
            //if(!a)printf("OK\n");
    		size[a]=size[son[a][0]]+size[son[a][1]]+1;
        }
        int new_code(int a) {
            size[++tot]=1;
            val[tot]=a;
           	key[tot]=rand();
           	return tot;
        }
        void ins(int a)
    	{
    		int x=0,y=0;
    		val_split(rt,a,x,y);
    		rt=merge(merge(x,new_code(a)),y);
    	}
    	void del(int a)
    	{
    		int x=0,y=0,z=0;
    		val_split(rt,a,x,z);
    		val_split(x,a-1,x,y);
    		y=merge(son[y][0],son[y][1]);
    		rt=merge(merge(x,y),z);
    	}
        int merge(int a, int b) {
            if (!a||!b)
                return a+b;
            if (key[a]<key[b])
    		{
                son[a][1]=merge(son[a][1],b);
                update(a);
                return a;
            } 
    		else 
    		{
                son[b][0]=merge(a,son[b][0]);
                update(b);
                return b;
            }
        }
        void val_split(int now,int k,int &x,int &y)
        {
        	if(!now)x=y=0;
        	else 
    		{if(val[now]<=k)
        	{
        		x=now;
        		val_split(son[now][1],k,son[now][1],y);
    		}
    		else
    		{
    			y=now;
    			val_split(son[now][0],k,x,son[now][0]);
    		}
    		update(now);
    		}
    	}
    	void kth_split(int now,int k,int &x,int &y)
    	{
    		if(!now)x=y=0;
        	else 
    		{if(k<=size[son[now][0]])
        	{
    			y=now;
    			kth_split(son[now][0],k,x,son[now][0]);
    		}
    		else
    		{
        		x=now;
        		kth_split(son[now][1],k-size[son[now][0]]-1,son[now][1],y);
    		}
    		update(now);
    		}
    	}
    	int kth(int now,int k)
    	{
    		while(1)
    		{
    			if(k<=size[son[now][0]])now=son[now][0];
    			else if(k==size[son[now][0]]+1)return now;
    			else k-=size[son[now][0]]+1,now=son[now][1];
    		}
    	}
    	int kth_find(int a)
    	{
    		int x=0,y=0,sum;
    		val_split(rt,a-1,x,y);
    		sum=size[x]+1;
    		rt=merge(x,y);
    		return sum;
    	 } 
    	 int val_find(int a)
    	 {
    	 	return val[kth(rt,a)];
    	 }
    	int pre(int a)
    	{
    		int x=0,y=0,sum;
    		val_split(rt,a-1,x,y);
    		sum=val[kth(x,size[x])];
    		rt=merge(x,y);
    		return sum;
    	}
    	int nxt(int a)
    	{
    		int x=0,y=0,sum;
    		val_split(rt,a,x,y);
    		sum=val[kth(y,1)];
    		rt=merge(x,y);
    		return sum;
    	}
        
    } tree;
    int main() 
    {
    	//freopen("P3369_6.in","r",stdin);
    	//freopen("ber.out","w",stdout);
    	int n,opt,a;
    	for(scanf("%d",&n);n--;)
    	{
    		scanf("%d%d",&opt,&a);
    		if(opt==1)
    		{
    			tree.ins(a);
    		}
    		if(opt==2)
    		{
    			tree.del(a);
    		}
    		if(opt==3)
    		{
    			printf("%d\n",tree.kth_find(a));
    		}
    		if(opt==4)
    		{
    			printf("%d\n",tree.val_find(a));
    		}
    		if(opt==5)
    		{
    			printf("%d\n",tree.pre(a));
    		}
    		if(opt==6)
    		{
    			printf("%d\n",tree.nxt(a));
    		}
    	}
    	
    }
    
  • 相关阅读:
    Mybatis中javaType和jdbcType对应关系
    spy日志
    mybatis批量插入和更新
    js打印方案
    js弹窗,父子窗口调用
    extjs4.1
    oracle开启远程连接访问
    javaweb打印
    Leetcode 392.判断子序列
    Leetcode 391.完美矩形
  • 原文地址:https://www.cnblogs.com/HYDcn666/p/15836603.html
Copyright © 2020-2023  润新知