ZOJ 2112 动态区间第K大(二分答案+线段树套Treap)
来源:互联网 发布:origin软件百度云 编辑:程序博客网 时间:2024/05/17 22:51
The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.
Your task is to write a program for this computer, which
- Reads N numbers from the input (1 <= N <= 50,000)
- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.
Input
The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.
The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format
Q i j k or
C i t
It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.
There're NO breakline between two continuous test cases.
Output
For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])
There're NO breakline between two continuous test cases.
Sample Input
2
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
3
6
(adviser)
Site: http://zhuzeyuan.hp.infoseek.co.jp/index.files/our_contest_20040619.htm
人生第一道树套树?
之所以打问号,是因为其实之前写二维线段树的时候,那个也可以相当于是线段树套线段树,所以严格意义来说这个不是第一个道题……
普通的区间第k大很简单,各种数据结构乱搞就行了,但是如果要支持修改的话就一定要树套树。之所以用了Treap,就是想多熟悉一下,毕竟之前平衡树用的太少了。然后具体思路也是很简单,外面虚建一棵线段树,作用就是把区间分段,分段的同时对于每一个区间都建立一棵Treap,用来维护子区间的大小关系。由于Treap支持删除和插入操作,所以相当于可以进行修改。这里,不明白树套树的要注意,每次插入和删除一个点,不仅仅是改变一个Treap,而是每一个包含该点的区间对应的Treap都要修改,可以类似参照之前写的二维线段树模板。
然后,虽然这么做了,但是这本身是不支持区间合并的,也就是说当问区间[l,r]的第k大的时候,如果之前分区间的时候,没有恰好分到这个区间,我们是无法直接输出结果的。所以说,我们得用二分答案。每次二分一个数字,在对应区间中找比他小的数字的个数,如果比他小的数字恰好为k,那么结果就一定大于等于这个数字。如此二分下去就可以得到结果。具体见代码:
#include<bits/stdc++.h>#define N 1000010using namespace std;int n,m,Rnk,a[N];struct Treap{ struct treap { int son[2],size,num,cnt,fix; } tree[N]; int sz,root[N]; inline void init() { sz=0; memset(tree,0,sizeof(tree)); memset(root,0,sizeof(root)); } inline void update(int x) { if (!x) return; tree[x].size=tree[x].cnt; if (tree[x].son[0]) tree[x].size+=tree[tree[x].son[0]].size; if (tree[x].son[1]) tree[x].size+=tree[tree[x].son[1]].size; } inline void Rotate(int &x,bool ch) { int y=tree[x].son[ch^1],z=x; tree[x].son[ch^1]=tree[y].son[ch]; tree[y].son[ch]=x; x=y; update(z); update(y); } inline void ins(int &i,int x) { if (!i) { i=++sz; tree[i].num=x; tree[i].fix=rand(); tree[i].size=tree[i].cnt=1; tree[i].son[0]=tree[i].son[1]=0; return; } tree[i].size++; if (tree[i].num==x) tree[i].cnt++; else { bool ch=(x>tree[i].num); ins(tree[i].son[ch],x); if (tree[tree[i].son[ch]].fix>tree[i].fix) Rotate(i,ch^1); } update(i); } inline void del(int &i,int x) { if (!i) return; if (tree[i].num==x) { if (tree[i].cnt>1) { tree[i].size--; tree[i].cnt--; return; } if (tree[i].son[0]*tree[i].son[1]==0) i=tree[i].son[1]+tree[i].son[0]; else { bool ch=(tree[tree[i].son[0]].fix>tree[i].fix); Rotate(i,ch); del(tree[i].son[ch],x); } } else if (x<tree[i].num) { del(tree[i].son[0],x); tree[i].size--; } else { del(tree[i].son[1],x); tree[i].size--; } if (i) update(i); } inline int getrank(int &i,int x) { int res=0; if (!i) return res; if (x>=tree[i].num) { res+=tree[i].cnt+getrank(tree[i].son[1],x); if (tree[i].son[0]) res+=tree[tree[i].son[0]].size; } else res=getrank(tree[i].son[0],x); return res; }} treap;inline void ins(int i,int l,int r,int x,int num){ treap.ins(treap.root[i],num); if (l==r) return; int mid=(l+r)>>1; if (mid>=x) ins(i<<1,l,mid,x,num); else ins(i<<1|1,mid+1,r,x,num);}inline void update(int i,int l,int r,int x,int his,int now){ treap.del(treap.root[i],his); treap.ins(treap.root[i],now); if (l==r) return; int mid=(l+r)>>1; if (mid>=x) update(i<<1,l,mid,x,his,now); else update(i<<1|1,mid+1,r,x,his,now);}inline void getrank(int i,int l,int r,int L,int R,int x){ if (l==L&&r==R) { Rnk+=treap.getrank(treap.root[i],x); return; } int mid=(l+r)>>1; if (mid>=R) getrank(i<<1,l,mid,L,R,x); else if (mid<L) getrank(i<<1|1,mid+1,r,L,R,x); else { getrank(i<<1,l,mid,L,mid,x); getrank(i<<1|1,mid+1,r,mid+1,R,x); }}int main(){ int T_T; cin>>T_T; srand(time(NULL)); while(T_T--) { scanf("%d%d",&n,&m); treap.init(); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); ins(1,1,n,i,a[i]); } char op[10]; for(int i=1;i<=m;i++) { scanf("%s",op); if (op[0]=='C') { int x,y; scanf("%d%d",&x,&y); update(1,1,n,x,a[x],y); a[x]=y; } else { int L,R,k; scanf("%d%d%d",&L,&R,&k); int l=0,r=1e9; while(l<=r) { int mid=(l+r)>>1; Rnk=0; getrank(1,1,n,L,R,mid); if (Rnk>=k) r=mid-1; else l=mid+1; } printf("%d\n",l); } } } return 0;}
- ZOJ 2112 动态区间第K大(二分答案+线段树套Treap)
- ZOJ 2112 Dynamic Rankings (动态区间第K大) (线段树套SBT+二分)
- ZOJ 2112 Dynamic Rankings(线段树套treap求动态第K大)
- hdu 5412 CRB and Queries(动态区间第k大值,区间能修改)(整体二分,树状数组套平衡树,线段树套treap)
- 【ZOJ】2112 Dynamic Rankings 动态第K大【线段树套treap】
- hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)
- [BZOJ 1901][ZOJ 2112]Dynamic Rankings(树状数组套主席树、动态区间第k大值查询)
- ZOJ 2112 Dynamic Rankings 树状数组套主席树 单点修改求动态区间第K大
- Zoj 2112 线段树套Treap
- ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)★★
- ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)
- zoj 2112 Dynamic Rankings(动态第k大,树状数组套主席树)
- zoj 2112 树状数组 套主席树 动态求区间 第k个数
- ZOJ 2112 Dynamic Rankings(动态求区间第k大+整体二分)
- 区间第k大(树状数组套值域线段树)
- 动态区间第k小(主席树+线段树套树状数组)
- ZOJ 2112 Dynamic Rankings 树状数组套主席树 动态第K大
- ZOJ 2112 Dynamic Rankings 动态区间第k大 分块
- SSO单点登录
- eclipse中安装activiti插件
- Dockerfile详解
- hibernate
- opencv读取视频与摄像头
- ZOJ 2112 动态区间第K大(二分答案+线段树套Treap)
- Java 多线程的通信
- Cassandra版本差异查询解决方案
- 程序员最核心的竞争力是什么?
- Java编程:删除 List 元素的三种正确方法
- ant增量编译打包java项目
- django 数据库连接模块解析及简单长连接改造
- TextView加载Html文本中的图片
- OCI-22053: 溢出错误的原因和解决方法