【搞基数据结构】【树套树】ZOJ2112 Dynamic Rankings kth_number
来源:互联网 发布:安卓版手机编程工具 编辑:程序博客网 时间:2024/06/06 00:41
动态查询区间第k小,包括两个操作Q x y k和C i j,查询区间x y的第k小和把第i个数安替换成j。
静态的区间k小可以用划分树或者归并树,动态的就只能树套树或者树状数组套主席树,树状数组套主席树暂时还没有写出来,这里讲一下树套树的两种写法。
首先考虑到线段树可以用于区间查询,而平衡树可以查询某个数字的名次【小于或者小于等于这个数字的个数】,这样考虑到用线段树套平衡树的方式实现查询某个数字在区间x y上的名次,于是得到建树方式是:按区间建立线段树,线段树的每一个结点建立一棵平衡树,因为无法直接查询第k小,那么只能采用二分答案的方式,查询数字区间x y上的名次,这样查询的总复杂度是二分答案一个logn,线段树上一个logn,平衡树上一个logn,总的复杂度就是log^3n;更新就是线段树的单点更新方式,对于结点每个平衡树先把原来的值删掉,再把新的值加上去,总复杂度是log^2n。空间复杂度,线段树一共logn层,每层n个结点,所以总的空间是nlogn。
还有另一种树套树的方式可以把查询的复杂度变成log^2n,不过要先离线读入然后离散化。
这里首先考虑如何用线段树查询整个数列的第k大,首先将数列离散化然后按值域建立一棵线段树,将每个点插入并维护区间里插入的数字个数,每次查询的时候先看左子树有没有k个数,如果有就查询左子树的第k小,否则去右子树查询第k-左子树,当线段树上的区间l==r时返回l就是离散化以后的答案。
区间查询的话,就是每个节点建一个下标平衡树,查询左子树有多少>=x && <=y的个数,超过k就在左子树查询,否则去右子树查询。
这种建树方式需要离线读入,如果要强制在线的话可以将值域建成一棵线段树,然后每次更新时不更新到底,而是打标记,需要查询时再向下建树,不过这种方法我没有实现过,因为不知道怎么打标记。
下面两个是两种不同建树方式的提交情况,0168是按下标建树,2535是按值建树。
我是采用线段树套treap,因为treap比较好写。
按下标建树:
int id(int l,int r){ return l+r | l!=r; }int tree[N<<1];struct treap{ int key,wht,count,sz,ch[2]; }tp[N*20];int nodecount;void init(){ tp[0].sz=0; tp[0].wht=-INF; tp[0].key=-1; nodecount=0; }void update(int x){ tp[x].sz=tp[tp[x].ch[0]].sz+tp[x].count+tp[tp[x].ch[1]].sz; }void rotate(int &x,int t){ int y=tp[x].ch[t]; tp[x].ch[t]=tp[y].ch[!t]; tp[y].ch[!t]=x; update(x); update(y); x=y;}void insert(int &x,int t){ if(! x) { x=++nodecount; tp[x].key=t; tp[x].wht=rand(); tp[x].count=1; tp[x].ch[0]=tp[x].ch[1]=0; }else if(tp[x].key==t) tp[x].count++; else { int k=tp[x].key<t; insert(tp[x].ch[k],t); if(tp[x].wht<tp[tp[x].ch[k]].wht) rotate(x,k); } update(x);}void erase(int &x,int t){ if(tp[x].key==t) { if(tp[x].count==1) { if(! tp[x].ch[0] && ! tp[x].ch[1]){ x=0; return; } rotate(x,tp[tp[x].ch[0]].wht<tp[tp[x].ch[1]].wht); erase(x,t); }else tp[x].count--; }else erase(tp[x].ch[tp[x].key<t],t); update(x);}int select(int x,int k){ if(! x) return 0; if(k<tp[x].key) return select(tp[x].ch[0],k); int q=0,p=tp[tp[x].ch[0]].sz+tp[x].count; if(k>tp[x].key) q=select(tp[x].ch[1],k); return p+q;}int a[N],n,m,ans;void treeinsert(int l,int r,int i,int x){ insert(tree[id(l,r)],x); if(l==r) return; int m=(l+r)>>1; if(i<=m) treeinsert(l,m,i,x); if(i>m) treeinsert(m+1,r,i,x);}void del(int l,int r,int i,int x){ erase(tree[id(l,r)],x); if(l==r) return; int m=(l+r)>>1; if(i<=m) del(l,m,i,x); if(i>m) del(m+1,r,i,x);}void query(int l,int r,int L,int R,int x){ if(L<=l && R>=r){ ans+=select(tree[id(l,r)],x); return; } int m=(l+r)>>1; if(L<=m) query(l,m,L,R,x); if(R>m) query(m+1,r,L,R,x);}int main(){ int tt; scanf("%d",&tt); while (tt--) { scanf("%d%d",&n,&m); init(); memset(tree,0,sizeof(tree)); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); treeinsert(1,n,i,a[i]); } while (m--) { char s[5]; int x,y,c; scanf("%s",s); if(s[0]=='C') { scanf("%d %d",&x,&y); del(1,n,x,a[x]); a[x]=y; treeinsert(1,n,x,a[x]); }else { scanf("%d %d %d",&x,&y,&c); int l=0,r=INF,mid; while (l<r) { ans=0; mid=(l+r)>>1; query(1,n,x,y,mid); if(ans<c) l=mid+1; else r=mid; } printf("%d\n",l); } } } return 0;}
按值建树:
#define N 60010#define M 10010struct treap{ int key,wht,count,sz,ch[2];}tp[N*15];int tree[N<<1];int nodecount,root;void init(){ tp[0].sz=0; tp[0].wht=-INF; nodecount=0; root=0;}void update(int x){tp[x].sz=tp[tp[x].ch[0]].sz+tp[x].count+tp[tp[x].ch[1]].sz;}void rotate(int &x,int t){ int y=tp[x].ch[t]; tp[x].ch[t]=tp[y].ch[!t]; tp[y].ch[!t]=x; update(x); update(y); x=y;}void insert(int &x,int t){ if(! x) { x=++nodecount; tp[x].key=t; tp[x].wht=rand(); tp[x].count=1; tp[x].ch[0]=tp[x].ch[1]=0; }else if(tp[x].key==t) tp[x].count++; else { int k=tp[x].key<t; insert(tp[x].ch[k],t); if(tp[x].wht<tp[tp[x].ch[k]].wht) rotate(x,k); } update(x);}void erase(int &x,int t){ if(tp[x].key==t) { if(tp[x].count==1) { if(! tp[x].ch[0] && ! tp[x].ch[1]) { x=0; return; } rotate(x,tp[tp[x].ch[0]].wht<tp[tp[x].ch[1]].wht); erase(x,t); } else tp[x].count--; } else erase(tp[x].ch[tp[x].key<t],t); update(x);}int select(int x,int t){ if(! x) return 0; if(tp[x].key>t) return select(tp[x].ch[0],t);return tp[x].count+tp[tp[x].ch[0]].sz+select(tp[x].ch[1],t);}int a[N],b[N],ord[M][5],lb;int n,m,tt;int search(int x){ int l=1,r=b[0],mid; while (l<=r){ mid=(l+r)>>1;if(b[mid]==x) return mid; if(b[mid]<x) l=mid+1; else r=mid-1;}}void treeinsert(int l,int r,int i,int x){insert(tree[IDX(l,r)],x); if(l==r) return; int m=(l+r)>>1;if(i<=m) treeinsert(l,m,i,x); else treeinsert(m+1,r,i,x);}void treedel(int l,int r,int i,int x){erase(tree[IDX(l,r)],x); if(l==r) return; int m=(l+r)>>1;if(i<=m) treedel(l,m,i,x); else treedel(m+1,r,i,x);}int query(int l,int r,int x,int y,int k){ if(l==r) return l; int m=(l+r)>>1; int ans=select(tree[IDX(l,m)],y)-select(tree[IDX(l,m)],x); if(ans>=k) return query(l,m,x,y,k); return query(m+1,r,x,y,k-ans);}int main (){scanf("%d",&tt);while (tt--){scanf("%d%d",&n,&m); b[0]=1; lb=0;memset(tree,0,sizeof(tree)); init();for(int i=1;i<=n;i++){ scanf("%d",&a[i]); b[++lb]=a[i]; }for(int i=1;i<=m;i++){char s[5]; int x,y,c; scanf("%s",s);if(s[0]=='Q'){ scanf("%d %d %d",&x,&y,&c); ord[i][1]=1; ord[i][2]=x; ord[i][3]=y; ord[i][4]=c;}else{ scanf("%d %d",&x,&y); ord[i][1]=2; ord[i][2]=x; ord[i][3]=y; b[++lb]=y;}}sort(b+1,b+1+lb);for(int i=1;i<=lb;i++) if(b[i]!=b[b[0]]) b[++b[0]]=b[i];for(int i=1;i<=n;i++){ a[i]=search(a[i]); treeinsert(1,b[0],a[i],i); }for(int i=1;i<=m;i++){if(ord[i][1]==1)printf("%d\n",b[query(1,b[0],ord[i][2]-1,ord[i][3],ord[i][4])]);else{ treedel(1,b[0],a[ord[i][2]],ord[i][2]); a[ord[i][2]]=search(ord[i][3]); treeinsert(1,b[0],a[ord[i][2]],ord[i][2]);}}}return 0;}
- 【搞基数据结构】【树套树】ZOJ2112 Dynamic Rankings kth_number
- zoj2112 Dynamic Rankings (主席树 || 树套树)
- ZOJ2112-Dynamic Rankings
- zoj2112 Dynamic Rankings
- 树套树之线段树套平衡树(ZOJ2112 Dynamic Rankings)
- ZOJ2112 Dynamic Rankings 线段树+平衡树
- ZOJ2112 Dynamic Rankings 解题报告【数据结构】【分块】
- [主席树]ZOJ2112 && BZOJ1901 Dynamic Rankings
- 【zoj2112】【线段树套平衡树】Dynamic Rankings
- zoj2112--Dynamic Rankings(树状数组+主席树)
- 【ZOJ2112】Dynamic Rankings-树状数组套主席树+离散化
- 【树状数组+主席树】BZOJ1901 [ZOJ2112]Dynamic Rankings
- 【ZOJ2112】Dynamic Rankings 树状数组套主席树
- zoj2112 Dynamic Rankings 单点修改区间第k小
- ZOJ2112-Dynamic Rankings(树状数组套主席树)
- zoj2112 Dynamic Rankings(整体二分+树状数组)
- ZOJ2011-Dynamic Rankings 树套树?
- [ZOJ2112][可持久化线段树(主席树)][树状数组]Dynamic Rankings[好题]
- 盖茨和他的微软-第三章
- 2655
- pat 1049 Counting Ones
- ApiDemos之Fragment使用案例
- java方面不错的书
- 【搞基数据结构】【树套树】ZOJ2112 Dynamic Rankings kth_number
- 1196
- 成功鲜有偶然:一览IT名人的教育成长经历
- 项目管理之敏捷开发-Scrum应用实战(一)
- Ubuntu12.04下安装Qt4和创建第一个Qt程序
- 组合查询(vb.net版,机房收费系统)
- String StringBuffer 将值传入方法 修改后 再打印 结果
- POCO C++库学习和分析 -- 进程
- The method of learning python