手写平衡树
看的是洛谷日报上的教程 结果因为求第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 }
#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; }
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