zoukankan      html  css  js  c++  java
  • Treap

    Treap

    treap是啥,是一种平衡树,tree+heap

    众所周知,二叉平衡树一旦退化,复杂度将会很可怕。

    treap则给每一个节点附上了一个随机的值,然后利用旋转操作,让这个二叉搜索树同时也满足堆的性质。期望下可以达到(O(nlog_n))的复杂度了。

    具体怎么实现呢

    大部分的操作和一般的二叉搜索树一样。

    插入

    void insert(int &p,int v){
    	if(!p){
    		p=New(v);
    		return ;
    	}
    	tr[p].size++;
    	if(v==tr[p].v){
    		tr[p].cnt++;
    		return ;
    	}
    	if(v<tr[p].v){
    		insert(tr[p].l,v);
    		if(tr[p].rv<tr[tr[p].l].rv){
    			rr(p);
    		}
    		return ;
    	}else{
    		insert(tr[p].r,v);
    		if(tr[p].rv<tr[tr[p].r].rv){
    			lr(p);
    		}
    	}
    	return ;
    }
    

    可以注意到多了判断儿子的随机权值是否满足堆的过程。

    删除

    void del(int &p,int v){
    	if(!p) return ;
    	tr[p].size--;
    	if(tr[p].v==v){
    		if(tr[p].cnt>1){
    			tr[p].cnt--;
    			return ;
    		}
    		if(!tr[p].l||!tr[p].r){
    			p=tr[p].l+tr[p].r;
    		}else{
    			if(tr[tr[p].l].rv>tr[tr[p].r].rv){
    				rr(p);
    				del(tr[p].r,v);
    			}else{
    				lr(p);
    				del(tr[p].l,v);
    			}
    		}
    		return ;
    	}
    	if(v<tr[p].v){
    		del(tr[p].l,v);
    	}else{
    		del(tr[p].r,v);
    	}
    }
    

    在连接左右儿子的时候需要判断是否满足堆的性质

    Lisa

    最经典的模板题了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c))f^=c=='-',c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
    }
    template<class T>inline void print(T x)
    {
        if(x<0)putchar('-'),x=-x;
        if(x>9)print(x/10);
        putchar('0'+x%10);
    }
    int n;
    int f;
    int x;
    struct tr{
    	int l;
    	int r;
    	int v;
    	int cnt;
    	int rv;
    	int size;
    }tr[200005];
    int ro;
    int cnt;
    int New(int val){
    	tr[++cnt].l=0;
    	tr[cnt].r=0;
    	tr[cnt].v=val;
    	tr[cnt].cnt=1;
    	tr[cnt].size=1;
    	tr[cnt].rv=rand();
    	return cnt;
    }
    void update(int x){
    	tr[x].size=tr[tr[x].l].size+tr[tr[x].r].size+tr[x].cnt;
    }
    void rr(int &p){
    	int q=tr[p].l;
    	tr[p].l=tr[q].r;
    	tr[q].r=p;
    	tr[q].size=tr[p].size;
    	update(p);
    	p=q;
    }
    void lr(int &p){
    	int q=tr[p].r;
    	tr[p].r=tr[q].l;
    	tr[q].l=p;
    	tr[q].size=tr[p].size;
    	update(p);
    	p=q;
    }
    void insert(int &p,int v){
    	if(!p){
    		p=New(v);
    		return ;
    	}
    	tr[p].size++;
    	if(v==tr[p].v){
    		tr[p].cnt++;
    		return ;
    	}
    	if(v<tr[p].v){
    		insert(tr[p].l,v);
    		if(tr[p].rv<tr[tr[p].l].rv){
    			rr(p);
    		}
    		return ;
    	}else{
    		insert(tr[p].r,v);
    		if(tr[p].rv<tr[tr[p].r].rv){
    			lr(p);
    		}
    	}
    	return ;
    }
    void del(int &p,int v){
    	if(!p) return ;
    	tr[p].size--;
    	if(tr[p].v==v){
    		if(tr[p].cnt>1){
    			tr[p].cnt--;
    			return ;
    		}
    		if(!tr[p].l||!tr[p].r){
    			p=tr[p].l+tr[p].r;
    		}else{
    			if(tr[tr[p].l].rv>tr[tr[p].r].rv){
    				rr(p);
    				del(tr[p].r,v);
    			}else{
    				lr(p);
    				del(tr[p].l,v);
    			}
    		}
    		return ;
    	}
    	if(v<tr[p].v){
    		del(tr[p].l,v);
    	}else{
    		del(tr[p].r,v);
    	}
    }
    int getpre(int v){
    	int p=ro;
    	int res=0;
    	while(p){
    		if(tr[p].v<v){
    			res=tr[p].v;
    			p=tr[p].r;
    		}else{
    			p=tr[p].l;
    		}
    	}
    	return res;
    }
    int getsuf(int v){
    	int p=ro;
    	int res=0;
    	while(p){
    		if(tr[p].v<v){
    			res=tr[p].v;
    			p=tr[p].r;
    		}else{
    			p=tr[p].l;
    		}
    	}
    	return res;
    }
    int getrank(int p,int v){
    	if(!p) return 0;
    	if(tr[p].v==v) return tr[tr[p].l].size+1;//这里扔的是size,这里扔的是左儿子
    	if(tr[p].v<v) return getrank(tr[p].r,v)+tr[tr[p].l].size+tr[p].cnt;
    	if(tr[p].v>v) return getrank(tr[p].l,v); 
    }
    int getval(int p,int v){
    	if(!p) return 0;
    	if(tr[tr[p].l].size>=v) return getval(tr[p].l,v);
    	if(tr[tr[p].l].size+tr[p].cnt>=v) return tr[p].v;
    	return getval(tr[p].r,v-tr[p].cnt-tr[tr[p].l].size);
    }
    int main(){
    	read(n);
    	for(int i=1;i<=n;++i){
    		read(f);
    		read(x);
    		if(f==1) insert(ro,x);
    		if(f==2) del(ro,x);
    		if(f==3) printf("%d
    ",getrank(ro,x));
    		if(f==4) printf("%d
    ",getval(ro,x));
    		if(f==5) printf("%d
    ",getpre(x));
    		if(f==6) printf("%d
    ",getsuf(x));
    		
    	}
    	return 0;
    }
    

    Rose只需要询问前驱和后继

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c))f^=c=='-',c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
    }
    template<class T>inline void print(T x)
    {
        if(x<0)putchar('-'),x=-x;
        if(x>9)print(x/10);
        putchar('0'+x%10);
    }
    int n;
    struct tr{
    	int l;int r;
    	int v;
    	int cnt;int rv;
    }tr[500000];
    int ro;
    int cnt;
    int a[500000];
    int New(int v){
    	tr[++cnt].l=0;
    	tr[cnt].r=0;
    	tr[cnt].v=v;
    	tr[cnt].cnt=1;
    	tr[cnt].rv=rand();
    	return cnt;
    }
    void rr(int &p){
    	int q=tr[p].l;
    	tr[p].l=tr[q].r;
    	tr[q].r=p;
    	p=q;
    	return ;
    }
    void lr(int &p){
    	int q=tr[p].r;
    	tr[p].r=tr[q].l;
    	tr[q].l=p;
    	p=q;
    	return ;
    }
    void insert(int &p,int v){
    	if(!p){
    		p=New(v);
    		return ;
    	}
    	if(tr[p].v==v){
    		tr[p].cnt++;
    		return ;
    	}
    	if(tr[p].v<v){
    		insert(tr[p].r,v);
    		if(tr[p].rv<tr[tr[p].r].rv){
    			lr(p);
    		}
    		return ;
    	}else{
    		insert(tr[p].l,v);
    		if(tr[p].rv<tr[tr[p].l].rv){
    			rr(p);
    		}
    		return ;
    	}
    }
    int getpre(int v){
    	int p=ro;
    	int res=999999999;
    	while(p){
    		if(tr[p].v<=v){
    			res=tr[p].v;
    			p=tr[p].r;
    		}else{
    			p=tr[p].l;
    		}
    	}
    	return res;
    }
    int getsuf(int v){
    	int p=ro;
    	int res=999999999;
    	while(p){
    		if(tr[p].v>=v){
    			res=tr[p].v;
    			p=tr[p].l;
    		}else{
    			p=tr[p].r;
    		}
    	}
    	return res;
    }
    int ans;
    int main(){
    	read(n);
    	read(ans);
    	insert(ro,ans);
    	for(int i=2;i<=n;++i){
    		read(a[i]);
    		
    		//if(i!=1)
    		ans+=min(abs(a[i]-getpre(a[i])),abs(getsuf(a[i])-a[i]));
    		//else{
    			//ans=a[i];
    	//	}
    		insert(ro,a[i]);
    	}
    	cout<<ans;
    	return 0;
    }
    

    Jennie

    注意一下前驱后缀的返回值

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<stack>
    #include<algorithm>
    #define int long long
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c))f^=c=='-',c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
    }
    template<class T>inline void print(T x)
    {
        if(x<0)putchar('-'),x=-x;
        if(x>9)print(x/10);
        putchar('0'+x%10);
    }
    int t;
    int ro;
    int cnt;
    struct tree{
    	int l;
    	int r;
    	int cnt;
    	int v;
    	int rv;
    }tr[1000005];
    int New(int x){
    	tr[++cnt].l=0;
    	tr[cnt].r=0;
    	tr[cnt].cnt=1;
    	tr[cnt].v=x;
    	tr[cnt].rv=rand();
    	return cnt;
    }
    void rr(int& p){
    	int q=tr[p].l;
    	tr[p].l=tr[q].r;
    	tr[q].r=p;
    	//tr[p].size=tr[q].size();
    	p=q;
    }
    void lr(int& p){
    	int q=tr[p].r;
    	tr[p].r=tr[q].l;
    	tr[q].l=p;
    	//tr[p].size=tr[q].size();
    	p=q;
    }
    void insert(int &p,int v){
    	if(!p) {
    		p=New(v);
    		return ;
    	}
    	if(v==tr[p].v){
    		tr[p].cnt++;
    		return ;
    	}
    	if(v<tr[p].v){
    		insert(tr[p].l,v);
    		if(tr[tr[p].l].rv>tr[p].rv){
    			rr(p);
    		}
    		return ;
    	}else{
    		insert(tr[p].r,v);
    		if(tr[tr[p].r].rv>tr[p].rv){
    			lr(p);
    		}
    		return ;
    	}
    }
    int cntt[2];
    void del(int &p,int v){
    	if(!p){
    		return ;
    	}
    	if(tr[p].v==v){
    		if(tr[p].cnt>1){
    			tr[p].cnt--;
    			return ;
    		}
    		if(!tr[p].l||!tr[p].r){
    			p=tr[p].l+tr[p].r;
    		}else{
    			if(tr[tr[p].l].rv>tr[tr[p].r].rv){
    				rr(p);
    				del(tr[p].r,v);
    			}else{
    				lr(p);
    				del(tr[p].l,v);
    			}
    		}
    		return ;
    	}
    	if(v<tr[p].v){
    		del(tr[p].l,v);
    	}
    	if(v>tr[p].v){
    		del(tr[p].r,v);
    	}
    }
    int getpre(int v){
    	int p=ro;
    	int res=-999999999;
    	while(p){
    		if(tr[p].v<=v){
    			res=tr[p].v;
    			p=tr[p].r;
    		}else{
    			p=tr[p].l;
    		}
    	}
    	return res;
    }
    int getsuf(int v){
    	int p=ro;
    	int res=999999999;
    	while(p){
    		//cout<<p<<endl;
    		if(tr[p].v>=v){
    			res=tr[p].v;
    			p=tr[p].l;
    		}else{
    			p=tr[p].r;
    		}
    	}
    	return res;
    }
    int n;
    int a,b;
    int ans;
    int mod=1000000;
    signed main(){
    	read(n);
    	for(int i=1;i<=n;++i){
    		//cout<<i<<endl;
    		read(a);read(b);
    		if(cntt[a^1]){
    			int pp=getpre(b);
    			int ss=getsuf(b);
    		//	cout<<"F";
    			if(b-pp<=ss-b){
    				ans+=b-pp;
    				ans%=mod;
    				del(ro,pp);
    			}else{
    				ans+=ss-b;
    				ans%=mod;
    				del(ro,ss);
    			}
    		//	cout<<ans<<endl;
    			cntt[a^1]--;
    		}else{
    			insert(ro,b);
    			cntt[a]++;
    		}
    	}
    	cout<<ans%mod;
    	return 0;
    }
    
  • 相关阅读:
    韩式英语
    Daily dictation 听课笔记
    words with same pronunciation
    you will need to restart eclipse for the changes to take effect. would you like to restart now?
    glottal stop(britain fountain mountain)
    education 的发音
    第一次用Matlab 的lamada语句
    SVN的switch命令
    String的split
    SVN模型仓库中的资源从一个地方移动到另一个地方的办法(很久才解决)
  • 原文地址:https://www.cnblogs.com/For-Miku/p/15506183.html
Copyright © 2011-2022 走看看