【bzoj3196】二逼平衡树【树套树】【线段树】【平衡树】【呵呵】
2015-02-17 16:31
357 查看
……
我承认我写change函数时确实213了- -
a[pos]应当在最后被修改,可我却忘了……
第一次交上去的时候爆了数组,WA了……
然后把数组开大,交上去,MLE了……
现在我证明长度为n的序列,他的平衡树节点数组只要开到(log(2,f(n))+1)*f(n)就绝对不会爆。
f(n)是指比n大的最小的2的幂,比如f(65535)=65536,f(65537)=2^17.
证明嘛,因为长16的线段树有5层,每层平衡树总数都是16……
下面放代码,请神犇轻喷- -
欢迎评论。
PS:区间后继的求法(区间前驱同理):当这个区间被线段树分成好几个区间之后,在这几个区间里分别求后继,然后取最小值。注意如果在某个区间里没有后继,则返回正无穷,以免影响答案。
我承认我写change函数时确实213了- -
a[pos]应当在最后被修改,可我却忘了……
第一次交上去的时候爆了数组,WA了……
然后把数组开大,交上去,MLE了……
现在我证明长度为n的序列,他的平衡树节点数组只要开到(log(2,f(n))+1)*f(n)就绝对不会爆。
f(n)是指比n大的最小的2的幂,比如f(65535)=65536,f(65537)=2^17.
证明嘛,因为长16的线段树有5层,每层平衡树总数都是16……
下面放代码,请神犇轻喷- -
欢迎评论。
#include<cstdio> #include<cstring> #include<iostream> #define mid (l+r>>1) using namespace std; const int maxn=1200000; typedef int arr[maxn]; int tot,m,n; arr l,r,s,d; int a[50001]; struct SBT{ int rt; SBT():rt(0){} void L(int &x){ int b=r[x]; r[x]=l[b]; l[b]=x; s[b]=s[x]; s[x]=s[l[x]]+s[r[x]]+1; x=b; } void R(int &x){ int b=l[x]; l[x]=r[b]; r[b]=x; s[b]=s[x]; s[x]=s[l[x]]+s[r[x]]+1; x=b; } void maintain(int &x,bool f){ if(!f){ if(s[l[l[x]]]>s[r[x]]) R(x); else if(s[r[l[x]]]>s[r[x]]) L(l[x]),R(x); else return; } else{ if(s[r[r[x]]]>s[l[x]]) L(x); else if(s[l[r[x]]]>s[l[x]]) R(r[x]),L(x); else return; } maintain(l[x],0); maintain(r[x],1); maintain(x,0); maintain(x,1); } void insert(int &x,int key){ if(!x){ x=++tot; s[x]=1; l[x]=r[x]=0; d[x]=key; } else{ s[x]++; insert(key<d[x]?l[x]:r[x],key); maintain(x,key>=d[x]); } } int del(int &x,int key){ s[x]--; if(key==d[x]||key<d[x]&&!l[x]||key>d[x]&&!r[x]){ int val=d[x]; if(!l[x]||!r[x]) x=l[x]+r[x]; else d[x]=del(l[x],key+1); return val; } return del(key<d[x]?l[x]:r[x],key); } int rank(int t,int key){ int ans=0;//因为要把多个区间的结果并起来,所以只返回比key小的数的个数。 while(t){ if(key<=d[t]) t=l[t]; else ans+=s[l[t]]+1,t=r[t]; } return ans; } int succ(int t,int key){ int f=0; while(t){ if(key<d[t]) f=t,t=l[t]; else t=r[t]; } return f?d[f]:0x1f1f1f1f; } int pred(int t,int key){ int f=0; while(t){ if(d[t]<key) f=t,t=r[t]; else t=l[t]; } return f?d[f]:-1; } void insert(int key){insert(rt,key); } void del (int key){del(rt,key); } int select(int k ){return select(rt,k);} int rank (int k ){return rank(rt,k); } int succ (int key){return succ(rt,key);} int pred (int key){return pred(rt,key);} }; //---------------------------------------------- //segment tree: arr lc,rc; SBT sbt[100000]; int stot=0,tree=0; void build(int &x,int l,int r){ x=++stot; for(int i=l;i<r;++i)//!!!!!!!!!!!!!!!!!!!! sbt[x].insert(a[i]); if(l+1<r){ build(lc[x],l,mid); build(rc[x],mid,r); } } void change(int x,int l,int r,int pos,int c){ if(l+1==r){ sbt[x].del(a[pos]); sbt[x].insert(c); a[pos]=c; return; } sbt[x].del(a[pos]); sbt[x].insert(c); if(pos<mid) change(lc[x],l,mid,pos,c); else change(rc[x],mid,r,pos,c); } int rank(int x,int l,int r,int L,int R,int key){ if(L<=l&&r<=R) return sbt[x].rank(key); int ans=0; if(L<mid) ans+=rank(lc[x],l,mid,L,R,key); if(R>mid) ans+=rank(rc[x],mid,r,L,R,key); return ans; } int succ(int x,int l,int r,int L,int R,int key){ if(L<=l&&r<=R) return sbt[x].succ(key); int ans=0x1f1f1f1f; if(L<mid) ans=min(ans,succ(lc[x],l,mid,L,R,key)); if(R>mid) ans=min(ans,succ(rc[x],mid,r,L,R,key)); return ans; } int pred(int x,int l,int r,int L,int R,int key){ if(L<=l&&r<=R) return sbt[x].pred(key); int ans=-1; if(L<mid) ans=max(ans,pred(lc[x],l,mid,L,R,key)); if(R>mid) ans=max(ans,pred(rc[x],mid,r,L,R,key)); return ans; } #undef mid inline int Select(int L,int R,int k){ int low=0,high=(int)1e8,tmpRank,mid; while(low<=high){ mid=low+high>>1; tmpRank=1+rank(1,1,n+1,L,R,mid); if(tmpRank>k) high=mid-1; else low=mid+1; } return high; } inline int Succ(int L,int R,int key){ return succ(1,1,n+1,L,R,key); } inline int Pred(int L,int R,int key){ return pred(1,1,n+1,L,R,key); } inline int Rank(int L,int R,int key){ return 1+rank(1,1,n+1,L,R,key); } inline void read(int &x){ x=0; bool f=false; char ch=getchar(); while((ch<'0'||ch>'9')&&ch!=-1){if(ch=='-') f=true;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();} if(f) x=-x; } int main(){ read(n),read(m); for(int i=1;i<=n;++i) read(a[i]); build(tree,1,n+1); int a,b,c,opt; while(m--){ read(opt); switch(opt){ case 1://求排名 read(a);read(b);read(c);//scanf("%d%d%d",&a,&b,&c); printf("%d\n",Rank(a,b+1,c)); break; case 2://求区间第k大 read(a);read(b);read(c);//scanf("%d%d%d",&a,&b,&c); printf("%d\n",Select(a,b+1,c)); break; case 3://修改元素的值 read(a);read(b);//scanf("%d%d",&a,&b); change(1,1,n+1,a,b); break; case 4://求区间前驱 read(a);read(b);read(c);//scanf("%d%d%d",&a,&b,&c); printf("%d\n",Pred(a,b+1,c)); break; case 5://求区间后继 read(a);read(b);read(c);//scanf("%d%d%d",&a,&b,&c); printf("%d\n",Succ(a,b+1,c)); } } return 0; }
PS:区间后继的求法(区间前驱同理):当这个区间被线段树分成好几个区间之后,在这几个区间里分别求后继,然后取最小值。注意如果在某个区间里没有后继,则返回正无穷,以免影响答案。
相关文章推荐
- BZOJ 3196: Tyvj 1730 二逼平衡树|线段树套平衡树
- BZOJ 3196 Tyvj 1730 二逼平衡树 线段树套splay
- BZOJ3196 3223 3224 二逼平衡树,文艺平衡树,普通平衡树
- BZOJ3196 二逼平衡树(线段树套线段树)
- BZOJ 3196 Tyvj 1730 二逼平衡树(线段树套treap)
- [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)
- bzoj3196 [TYVJ1730]二逼平衡树 树套树 线段树套替罪羊树
- [BZOJ3196]二逼平衡树(线段树套splay)
- 【BZOJ 3196】二逼平衡树 线段树套splay 模板题
- BZOJ 3196 二逼平衡树 树套树(线段树套Treap)
- [BZOJ3196]二逼平衡树(线段树套splay)
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
- [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】
- 树套树之线段树套平衡树(BZOJ3196、洛谷3380)
- [bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)
- BZOJ 3196(Tyvj 1730 二逼平衡树-线段树套Treap)
- 【bzoj3196】【坑】Tyvj 1730 二逼平衡树 线段树套Treap/Splay
- 【BZOJ3196】Tyvj 1730 二逼平衡树 线段树套Treap
- bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】
- 【BZOJ3196】二逼平衡树(树状数组,线段树)