沉迷数据结构1(treap&非旋treap)

Posted shixinyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了沉迷数据结构1(treap&非旋treap)相关的知识,希望对你有一定的参考价值。

Achen大佬说不要沉迷数据结构否则智商会降低的。

从省选考完后就开始学treap,首先是自己yy了一个打了两百多行,然后debug了2个月还是3个月记不清了。

最后弃疗,去找了网上别人的代码抄了一遍。

noip考完后补常规的一段时间,羡慕Achen能20分钟打出一个treap模板,于是自己也开始走上打板子的不归路。

到了后来可以10分钟左右打出一个结构体版的treap,看了Achen的数组版treap,觉得自己结构体版的太不优秀啦,于是就换成数组版的。

然后现在有几周没有碰过treap,感觉又不会打了。。。。不过还好,大概看一下又想起来了。

先放个板子。

结构体版:

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<ctime>
using namespace std;
const int maxn=100000+10;
int n,tot=0,ans1,ans2,root;

int aa,ff;char cc;
int read() {
    aa=0;ff=1;cc=getchar();
    while((cc<‘0‘||cc>‘9‘)&&cc!=‘-‘) cc=getchar();
    if(cc==‘-‘) ff=-1,cc=getchar();
    while(cc>=‘0‘&&cc<=‘9‘) aa=aa*10+cc-‘0‘,cc=getchar();
    return aa*ff;
}

struct Node{
    int num,rnd,son[2],sum,x;
}node[maxn];

void rotate(int &pos,int p) {
    int s=node[pos].son[p];
    node[s].sum=node[pos].sum;
    node[pos].son[p]=node[s].son[!p];
    node[s].son[!p]=pos;
    node[pos].sum=node[pos].x+node[node[pos].son[0]].sum+node[node[pos].son[1]].sum;
    pos=s;
}

void add(int &pos,int x) {
    if(!pos) {
        pos=++tot;node[pos].num=x;node[pos].rnd=rand();
        node[pos].sum=node[pos].x=1;
        return ;
    }
    node[pos].sum++;
    if(node[pos].num==x) {
        node[pos].x++; return;
    }
    int p=x>node[pos].num;
    add(node[pos].son[p],x);
    if(node[node[pos].son[p]].rnd<node[pos].rnd) rotate(pos,p);
}

void del(int &pos,int x) {
    if(!pos) return;
    if(node[pos].num==x) {
        if(node[pos].x>1) {
            node[pos].x--;node[pos].sum--;return;
        }
        if(node[pos].son[0]*node[pos].son[1]==0) {
            pos=node[pos].son[0]+node[pos].son[1]; return;
        }
        int p= node[node[pos].son[1]].rnd<node[node[pos].son[0]].rnd;
        rotate(pos,p);
        node[pos].sum--;
        del(node[pos].son[!p],x);
    }
    else {
        node[pos].sum--;
        if(node[pos].num>x) del(node[pos].son[0],x);
        else del(node[pos].son[1],x);
    }
}

int qrank(int pos,int x) {
    if(node[pos].num==x) return node[node[pos].son[0]].sum+1;
    if(node[pos].num>x) return qrank(node[pos].son[0],x);
    return node[node[pos].son[0]].sum+node[pos].x+qrank(node[pos].son[1],x);
}

int qnum(int pos,int x) {
    if(x>node[node[pos].son[0]].sum&&x<=node[node[pos].son[0]].sum+node[pos].x) return node[pos].num;
    if(x<=node[node[pos].son[0]].sum) return qnum(node[pos].son[0],x);
    return qnum(node[pos].son[1],x-node[pos].x-node[node[pos].son[0]].sum);
}

void q1(int pos,int x) {
    if(!pos) return;
    if(x>node[pos].num) {
        ans1=node[pos].num;
        q1(node[pos].son[1],x);
    }
    else q1(node[pos].son[0],x);
}

void q2(int pos,int x) {
    if(!pos) return;
    if(x<node[pos].num) {
        ans2=node[pos].num;
        q2(node[pos].son[0],x);
    }
    else q2(node[pos].son[1],x);
}

int main() {
    srand((unsigned)time(NULL));
    n=read();
    int opt,x,y;
    for(int i=1;i<=n;++i) {
        opt=read();x=read();
        if(opt==1) add(root,x);
        else if(opt==2) del(root,x);
        else if(opt==3) printf("%d\n",qrank(root,x));
        else if(opt==4) printf("%d\n",qnum(root,x));
        else if(opt==5) q1(root,x),printf("%d\n",ans1);
        else q2(root,x),printf("%d\n",ans2);
    }
    return 0;
}

数组版:

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1e5+10;
int n,tot,root,ans;
int sum[maxn],num[maxn],rnd[maxn],fx[maxn],son[maxn][2];

int aa,ff;char cc;
int read() {
    aa=0;cc=getchar();ff=1;
    while(cc<‘0‘||cc>‘9‘) {
        if(cc==‘-‘) ff=-1;
        cc=getchar();
    }
    while(cc>=‘0‘&&cc<=‘9‘) aa=aa*10+cc-‘0‘,cc=getchar();
    return aa*ff;
}

void rotate(int &pos,int p) {
    int s=son[pos][p];
    sum[s]=sum[pos];
    son[pos][p]=son[s][!p];
    son[s][!p]=pos;
    sum[pos]=sum[son[pos][0]]+sum[son[pos][1]]+fx[pos];
    pos=s;
}

void add(int &pos,int x) {
    if(!pos) {
        pos=++tot;
        num[pos]=x;
        rnd[pos]=rand();
    }
    sum[pos]++;
    if(num[pos]==x) {
        fx[pos]++;
        return;
    }
    int p=x>num[pos];
    add(son[pos][p],x);
    if(rnd[son[pos][p]]<rnd[pos]) rotate(pos,p);
}

void del(int &pos,int x) {
    if(!pos) return;
    if(num[pos]==x) {
        if(fx[pos]>1) {
            fx[pos]--;
            sum[pos]--;
            return;
        }
        if(son[pos][0]*son[pos][1]==0) {
            pos=son[pos][0]+son[pos][1];
            return;
        }
        int p=rnd[son[pos][1]]<rnd[son[pos][0]];
        rotate(pos,p);sum[pos]--;
        del(son[pos][!p],x);
    }
    else {
        sum[pos]--;
        del(son[pos][x>num[pos]],x);
    }
}

int qnum(int pos,int x) {
    if(x>sum[son[pos][0]]&&x<=sum[son[pos][0]]+fx[pos]) return num[pos];
    if(x<=sum[son[pos][0]]) return qnum(son[pos][0],x);
    return qnum(son[pos][1],x-sum[son[pos][0]]-fx[pos]);
}

int qrank(int pos,int x) {
    if(x==num[pos]) return sum[son[pos][0]]+1;
    if(x<num[pos]) return qrank(son[pos][0],x);
    return sum[son[pos][0]]+fx[pos]+qrank(son[pos][1],x);
}

void q1(int pos,int x) {
    if(!pos) return;
    if(num[pos]<x) ans=num[pos],q1(son[pos][1],x);
    else q1(son[pos][0],x);
}

void q2(int pos,int x) {
    if(!pos) return;
    if(num[pos]>x) ans=num[pos],q2(son[pos][0],x);
    else q2(son[pos][1],x);
}
int main() {
    srand(1031);
    n=read();
    int op,x;
    for(int i=1;i<=n;++i) {
        op=read();x=read();
        switch(op) {
            case 1:add(root,x);break;
            case 2:del(root,x);break;
            case 3:printf("%d\n",qrank(root,x));break;
            case 4:printf("%d\n",qnum(root,x));break;
            case 5:q1(root,x);printf("%d\n",ans);break;
            case 6:q2(root,x);printf("%d\n",ans);break;
        }
    }
    return 0;
}

 

 

而非旋treap支持split和merge很是有趣,这次直接照着Achen的板子学,感受到Achen大佬的数据结构多么优秀。

merge的时候不想用pair然后就乱搞了一搞,调了一阵子,最后强制把代码改成自己的码风。感觉不是很难打。

 

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define lc son[pos][0]
#define rc son[pos][1]
const int maxn=1e5+10,base=28;
int n,root,tot,ans;
int son[maxn][2],num[maxn],sum[maxn],rnd[maxn];

int aa,ff;char cc;
int read() {
	aa=0;ff=1;cc=getchar();
	while(cc!=‘-‘&&(cc<‘0‘||cc>‘9‘)) cc=getchar();
	if(cc==‘-‘) ff=-1,cc=getchar();
	while(cc>=‘0‘&&cc<=‘9‘) aa=aa*10+cc-‘0‘,cc=getchar();
	return aa*ff;
}

void ud(int pos){sum[pos]=sum[lc]+sum[rc]+1;}
ll pr(int x,int y) {return ((ll)x<<base)+(ll)y;}//第一个ll要套在里面 
int fi(ll x){return x>>base;}
int se(ll x){return x-((ll)fi(x)<<base);}

int merge(int x,int y) {
	if((ll)x*y==0) return x^y;
	if(rnd[x]<rnd[y]) return son[x][1]=merge(son[x][1],y),ud(x),x;
	else return son[y][0]=merge(x,son[y][0]),ud(y),y;
}

ll split(int pos,int x) {
	if(!pos) return 0;
	ll rs;
	if(sum[lc]>=x) {
		rs=split(lc,x);
		lc=se(rs);
		rs=pr(fi(rs),pos);
	}
	else {
		rs=split(rc,x-sum[lc]-1);
		rc=fi(rs);
		rs=pr(pos,se(rs));
	}
	return ud(pos),rs;
}

int qrank(int pos,int x) {
	if(!pos) return 1;
	if(num[pos]<x) return sum[lc]+1+qrank(rc,x);
	return qrank(lc,x);
}

int qnum(int pos,int x) {
	if(x==sum[lc]+1) return num[pos];
	if(x<=sum[lc]) return qnum(lc,x);
	return qnum(rc,x-sum[lc]-1);
}

void q1(int pos,int x) {
    if(!pos) return;
    if(num[pos]<x) ans=num[pos],q1(son[pos][1],x);
    else q1(son[pos][0],x);
}
 
void q2(int pos,int x) {
    if(!pos) return;
    if(num[pos]>x) ans=num[pos],q2(son[pos][0],x);
    else q2(son[pos][1],x);
}

void add(int &pos,int x) {
	int k=qrank(pos,x); ++tot;
	num[tot]=x;sum[tot]=1;rnd[tot]=rand();
	ll p=split(pos,k-1);
	pos=merge(fi(p),tot);
	pos=merge(pos,se(p));
}

void del(int &pos,int x) {
	int k=qrank(pos,x);
	ll p=split(pos,k-1);
	ll q=split(se(p),1);
	pos=merge(fi(p),se(q));
}

int main() {
	srand(1031);n=read();
	int op,x;
	while(n--) {
		op=read(); x=read();
		switch(op) {
			case 1:add(root,x);break;
			case 2:del(root,x);break;
			case 3:printf("%d\n",qrank(root,x));break;
			case 4:printf("%d\n",qnum(root,x));break;
			case 5:q1(root,x);printf("%d\n",ans);break;
            case 6:q2(root,x);printf("%d\n",ans);break;
		}
	}
	return 0;
}

 

  

 

以上是关于沉迷数据结构1(treap&非旋treap)的主要内容,如果未能解决你的问题,请参考以下文章

非旋Treap总结 : 快过Splay 好用过传统Treap

全网最详细的fhq treap (非旋treap)讲解

非旋Treap

非旋 treap 结构体数组版(无指针)详解,有图有真相

非旋 treap 结构体数组版(无指针)详解,有图有真相

非旋treap