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;
}