【luogu3369】【模板】普通平衡树 [平衡树]

luogu3369

手写平衡树

看的是洛谷日报上的教程  结果因为求第k大时那个判断就出了错导致时间超限 惨烈

然后还要注意开始要插入一个极大值和极小值

  1 /*
  2 id:gww
  3 language:C--
  4    
  5 */
  6 #include<bits/stdc++.h>
  7 using namespace std;
  8 const int N=200005;
  9 int ch[N][2],val[N],cnt[N],par[N],size[N];
 10 int root,ncnt=0;
 11 //0 1代表 x的左 右儿子 val[x] x存储的值 
 12 //cnt[x] x存储的重复权值的个数 par[x]代表 x的父节点 
 13 //size[x]代表 x子树下的储存的权值数(包括重复权值)
 14 inline int rd()
 15 {
 16     int x=0,w=0;char ch=0;
 17     while(!isdigit(ch)) w|=ch=='-',ch=getchar();
 18     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
 19     return w?-x:x;
 20 }
 21 
 22 void pushup(int x) {size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];}//更新size数组 
 23 bool chk(int x) {return ch[par[x]][1]==x;}//判断x位于它父亲的方向 
 24 
 25 void rotate(int x)//旋转 将被指定节点向上移动一级 
 26 {
 27     int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
 28     ch[y][k]=w;par[w]=y; 
 29 //父节点连向需旋转的该子节点的方向的边连向该子节点位于其父节点方向的反方向的节点
 30     ch[z][chk(y)]=x;par[x]=z;
 31 //爷爷节点连向父节点的边连向需旋转的该节点
 32     ch[x][k^1]=y;par[y]=x;
 33 //需旋转的该节点连向该子节点位于其父节点方向的反方向的子节点的边连向其父节点
 34     pushup(y);pushup(x);
 35 }
 36 
 37 void splay(int x,int goal=0)//伸展 
 38 {
 39     while(par[x]!=goal)
 40     {
 41         int y=par[x],z=par[y];
 42         if(z!=goal)
 43         {
 44             if(chk(x)==chk(y)) rotate(y);//三点一线 转父亲
 45             else rotate(x);
 46         }
 47         rotate(x); 
 48     }
 49     if(!goal) root=x;
 50 }
 51 
 52 void find(int x)//将最大的小于等于x的数所在的节点splay到根
 53 {
 54 //    if(!root) return;
 55     int cur=root;
 56     while(val[cur]!=x&&ch[cur][x>val[cur]]) {cur=ch[cur][x>val[cur]];}
 57     splay(cur);
 58 }
 59 
 60 void insert(int x)//插入 
 61 {
 62     int cur=root,p=0;//从根节点开始
 63     while(val[cur]!=x&&cur) {p=cur;cur=ch[cur][x>val[cur]];} //不存在 新建节点并与父节点连边
 64     if(cur) cnt[cur]++;//节点存在则直接自增cnt的值
 65     else//新建节点时可能会拉出一条链,
 66     {
 67         cur=++ncnt;
 68         if(p) ch[p][x>val[p]]=cur;
 69         par[cur]=p;val[cur]=x;
 70         ch[cur][0]=ch[cur][1]=0;
 71         size[cur]=cnt[cur]=1;
 72     }
 73     splay(cur);//所以新建节点后需要将该节点splay到根节点
 74 }
 75 
 76 int kth(int k)
 77 {
 78     int cur=root;
 79     while(1)
 80     {
 81         if (ch[cur][0] && k <= size[ch[cur][0]]) {cur = ch[cur][0];}
 82         else if (k > size[ch[cur][0]] + cnt[cur]) 
 83         {
 84             k-=size[ch[cur][0]]+cnt[cur];
 85             cur=ch[cur][1];
 86         }
 87         else {return cur;}
 88     }
 89 }
 90 
 91 int pre(int x)//前驱 小于这个值并且最接近这个值的元素值
 92 {
 93     find(x);//先初始化一个最值
 94     if(val[root]<x) return root;
 95     int cur=ch[root][0];//向下走 
 96     while(ch[cur][1]) cur=ch[cur][1];
 97     return cur; 
 98 }
 99 int succ(int x)//后继 大于这个值并且最接近这个值的元素值 
100 {
101     find(x);//先初始化一个最值
102     if(val[root]>x) return root;
103     int cur=ch[root][1];//向下走 
104     while(ch[cur][0]) cur=ch[cur][0];
105     return cur; 
106  } 
107 
108 void remove(int x)
109 {//把前驱splay到根,后继splay到前驱的右儿子,那么后继的左儿子就是要删除的点
110     int last=pre(x),nxt=succ(x);
111     splay(last);splay(nxt,last);
112     int del=ch[nxt][0];
113     if(cnt[del]>1) {cnt[del]--;splay(del);}
114     else {ch[nxt][0]=0;}
115 }
116 
117 int getrank(int x)
118 {
119     find(x);
120     return size[ch[root][0]];
121 }
122 
123 int main()
124 {
125     int t=rd();
126     insert(1e9);
127     insert(-1e9);
128     while(t--)
129     {
130         int opt=rd(),x=rd();
131         if(opt==1) insert(x);
132         if(opt==2) remove(x);
133         if(opt==3) printf("%d
",getrank(x));
134         if(opt==4) printf("%d
",val[kth(x+1)]);
135         if(opt==5) printf("%d
",val[pre(x)]);
136         if(opt==6) printf("%d
",val[succ(x)]);
137     }
138     return 0;
139 }
100昏
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,INF=1e9+7,inf=0x3f3f3f3f;
int n,root,tot=0,op,x;
int size[N],ch[N][2],par[N],val[N],cnt[N];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

void pushup(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];}
int chk(int x){return ch[par[x]][1]==x;}

void rotate(int x){
    int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
    ch[y][k]=w,par[w]=y;
    ch[z][chk(y)]=x,par[x]=z;
    ch[x][k^1]=y,par[y]=x;
    pushup(y),pushup(x);
}

void splay(int x,int goal){
    while(par[x]!=goal){
        int y=par[x],z=par[y];
        if(z!=goal) (chk(x)==chk(y))?rotate(y):rotate(x);
        rotate(x);
    }
    if(!goal) root=x;
}

void find(int x){//将最大的小于等于x的数所在的节点splay到根
    int cur=root;
    while(ch[cur][x>val[cur]]&&val[cur]!=x) cur=ch[cur][x>val[cur]];
    splay(cur,0);
}

void insert(int x){
    int cur=root,f=0;
    while(cur&&val[cur]!=x) f=cur,cur=ch[cur][x>val[cur]];//当u存在并且没有移动到当前的值
    if(cur) ++cnt[cur];
    else{
        cur=++tot;
        if(f) ch[f][x>val[f]]=cur;
        par[cur]=f,val[cur]=x;
        size[cur]=cnt[cur]=1;
        ch[cur][0]=ch[cur][1]=0;
    }
    splay(cur,0);
}

int kth(int k){
    int cur=root;
    while(1){
        if(ch[cur][0]&&k<=size[ch[cur][0]]) cur=ch[cur][0];
        else if(k>size[ch[cur][0]]+cnt[cur]) k-=size[ch[cur][0]]+cnt[cur],cur=ch[cur][1];
        else return cur;
    }
}

int Nxt(int x,int fla){
    find(x);
    int cur=root;
    if(val[cur]>x&&fla) return cur;
    if(val[cur]<x&&!fla) return cur;
    cur=ch[cur][fla];
    while(ch[cur][fla^1]) cur=ch[cur][fla^1];
    return cur;
}

void remove(int x){
    int pre=Nxt(x,0),nxt=Nxt(x,1);
    splay(pre,0),splay(nxt,pre);
    int del=ch[nxt][0];
    if(cnt[del]>1) --cnt[del],splay(del,0);
    else ch[nxt][0]=0;
}

int getrank(int x){
    find(x);
    return size[ch[root][0]];
}

int main(){
    freopen("in.txt","r",stdin);
    rd(n);
    insert(INF),insert(-INF);
    while(n--){
        rd(op),rd(x);
        if(op==1) insert(x);
        else if(op==2) remove(x);
        else if(op==3) printf("%d
",getrank(x));
        else if(op==4) printf("%d
",val[kth(x+1)]);
        else if(op==5) printf("%d
",val[Nxt(x,0)]);
        else if(op==6) printf("%d
",val[Nxt(x,1)]);
    }
    return 0;
}
2019.8.11

something from yyb

vector版平衡树

  • lower_bound(first,last,x)在first和last中的前闭后开区间进行查找,其中如果寻找的x存在,那么lower_bound返回一个迭代器指向其中第一个x元素。

    时间复杂度:O(logN)

  • upper_bound(first,last,x)在first和last中的前闭后开区间进行查找,返回一个迭代器指向最后一个x元素的下一个位置(就是说返回在保持顺序的情况下,可插入x的最后一个位置或者说就是返回x的后继)

    时间复杂度:O(logN)

  • vector.insert(pos,x)在pos处插入一个x

    vector.erase(pos,x)在删除pos处的x

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
const int N=200000+5,M=1000000+5,inf=0x3f3f3f3f,P=19650827;
int n;
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

vector<int>vec;
int main(){
    rd(n);
    while(n--){
        int op,x;
        rd(op),rd(x);
        if(op==1) vec.insert(upper_bound(vec.begin(),vec.end(),x),x);
        else if(op==2) vec.erase(lower_bound(vec.begin(),vec.end(),x));
        else if(op==3) printf("%d
",lower_bound(vec.begin(),vec.end(),x)-vec.begin()+1);
        else if(op==4) printf("%d
",vec[x-1]);
        else if(op==5) printf("%d
",*(--lower_bound(vec.begin(),vec.end(),x)));
        else if(op==6) printf("%d
",*upper_bound(vec.begin(),vec.end(),x));
    }
    return 0;
}

 multiset实现

vector效率比multiset高很多 所以vector能过

  • distance(pos1,pos2)返回一个int值为pos1与pos2之间的距离,pos1,pos2为指向同一容器的迭代器。 时间复杂度:O(N)

  • advance(pos,k)一个void的函数,让pos这个迭代器前进k步 时间复杂度:O(N)

  • set.equal_range(x),它返回的一队迭代器,因此是pair类型,定义时需注意。

    具体用法详见这: http://blog.csdn.net/zhongguoren666/article/details/8463249

    时间复杂度:O(logN)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<set>
using namespace std;
#define ll long long
const int N=200000+5,M=1000000+5,inf=0x3f3f3f3f,P=19650827;
int n,op,x;
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

//vector<int>vec;
multiset<int>mul;
int main(){
    rd(n);
    multiset<int>::iterator it;
    while(n--){
        rd(op),rd(x);
        if(op==1) mul.insert(x);
        else if(op==2) mul.erase(mul.lower_bound(x));
        else if(op==3) printf("%d
",distance(mul.begin(),mul.lower_bound(x))+1);
        else if(op==4) it=mul.begin(),advance(it,x-1),printf("%d
",*it);
        else if(op==5) printf("%d
",*(--mul.lower_bound(x)));
        else if(op==6) printf("%d
",*(mul.upper_bound(x)));
    }
    return 0;
}

jio落里放一下男神的

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<stack>
#include<algorithm>
#define rg register
#define ll long long
#define LDB long double
#define ull unsigned long long
#define view(i,x) for(rg int i=hd[x];i!=-1;i=e[i].nt)
#define go(i,x,a) for(rg int i=a;i<x;i++)
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
using namespace std;

const int maxn=1e5+5;
int n,tt,rt;
struct pt{
    int l,r,val,rnd,siz;
}t[maxn*2];

inline int rd(){
    int ret=0,af=1; char gc=getchar();
    while(gc < '0' || gc > '9'){ if(gc=='-') af=-af; gc=getchar(); }
    while(gc >= '0' && gc <= '9') ret=ret*10+gc-'0',gc=getchar();
    return ret*af;
}

inline int new_node(int x){
    t[++tt].val=x; t[tt].rnd=rand();
    t[tt].l=t[tt].r=0; t[tt].siz=1;
    return tt;
}

inline void update(int x){
    t[x].siz=t[t[x].l].siz+t[t[x].r].siz+1;
}
/* 
inline void split_siz(int a,int k,int &x,int &y){
    if(a==0){ x=0; y=0; return; }
    int s=t[t[a].l].siz;
    if(k > s) x=a,split_siz(t[x].r,k-s-1,t[x].r,y);
    else y=a,split_siz(t[x].l,k,x,t[x].l);
    update(a);
}*/ 

inline void split(int a,int k,int &x,int &y){
    if(a==0){ x=y=0; return ; }
    int w=t[a].val;
    if(w <= k) x=a,split(t[a].r,k,t[a].r,y);
    else y=a,split(t[a].l,k,x,t[a].l);
    update(a);
}

inline int merge(int x,int y){
    if(!x || !y) return x|y;
    if(t[x].val > t[y].val) swap(x,y);
    if(t[x].rnd < t[y].rnd){ t[x].r=merge(t[x].r,y); update(x); return x; }
    else{ t[y].l=merge(x,t[y].l); update(y); return y; }
}

inline void insert(int a){
    int x,y; split(rt,a,x,y);
    rt=merge(merge(x,new_node(a)),y);
}

inline void del(int a){
    int x,y,z,d;
    split(rt,a,x,z);
    split(x,a-1,d,y); 
    x=d;
    rt=merge(merge(x,merge(t[y].l,t[y].r)),z);
}

inline int get(int a){
    int x,y; split(rt,a-1,x,y);
    int q=t[x].siz; rt=merge(x,y);
    return q+1;
}

inline int find(int a,int k){
    int now=a;
    while(1){
        if(k <= t[t[now].l].siz) now=t[now].l;
        else{
            if(k == t[t[now].l].siz+1) return now;
            k=k-t[t[now].l].siz-1; now=t[now].r;
        }
    } 
}

inline int pre(int a){
    int x,y; split(rt,a-1,x,y);
    int q=find(x,t[x].siz); rt=merge(x,y);
    return t[q].val;
}

inline int suc(int a){
    int x,y; split(rt,a,x,y);
    int q=find(y,1); rt=merge(x,y);
    return t[q].val;
}

int main(){
    n=rd(); int fl,a;
    go(i,n+1,1){
        fl=rd(); a=rd();
        switch(fl){
            case 1:insert(a); break;
            case 2:del(a); break;
            case 3:printf("%d
",get(a)); break;
            case 4:printf("%d
",t[find(rt,a)].val); break;
            case 5:printf("%d
",pre(a)); break;
            case 6:printf("%d
",suc(a)); break;
        }
    }
    return 0;
}//Faze
View Code
原文地址:https://www.cnblogs.com/lxyyyy/p/10383932.html