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;
    }
    
  • 相关阅读:
    [Angular] How to show global loading spinner for application between page navigation
    [NgRx] NgRx Data Fetching Solution
    [NgRx] NgRx Entity Adapter Configuration
    [Javascript] Construct a Regex to Match Twitter Mentions with Regexr
    [Dart] Dynamic variable in Dart
    [NgRx] NgRx Runtime Checks
    [NgRx] Setting up NgRx Router Store and the Time-Travelling Debugger
    浅析数据库设计三范式
    建议别买三星Gear:半电脑产品 设计糟糕
    持续集成理论和实践的新进展
  • 原文地址:https://www.cnblogs.com/For-Miku/p/15506183.html
Copyright © 2011-2022 走看看