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);
}
}
在连接左右儿子的时候需要判断是否满足堆的性质
最经典的模板题了
#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;
}
注意一下前驱后缀的返回值
#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;
}