zoj-2112-Dynamic Rankings主席树模板
来源:互联网 发布:对社区网络式管理创新 编辑:程序博客网 时间:2024/06/05 10:57
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
总算是A了第一道主席树了,主席树的总体思想就是用n颗线段树(n是数组长度,并且这n颗线段树的结构是一模一样的,都是0-num)去维护一个前缀和,对于没有修改的主席树只需要维护一个T[i] 就够了,其中T[i] 表示第i颗线段树 当前已经插入了i个数,线段树的总共num个节点,(num是数组里面的数加上修改后的数去重以后得到的长度,由于数很大,要把所有的数哈希),线段树维护的是该区间数的个数,因为线段树里面的叶子节点是从小到大排序的,所有要查找第k大的数的时候若线段树左子树数的总数小于k那么第k大的一定在右子树,然后k-=左子树数的总数查找右子树,否则就在左子树查找左子树。
现在要查找的是在l到r的第k大的数,因为第i颗线段树表示当前这颗线段树已经插入了1至i的这些数,因为l至r区间应该是一颗只插入了第l至r的数的线段树,而这颗线段树可以用
T[r] - T[l-1]表示,于是这颗树的左子树的数的总数就等于第r颗树的左子树的数的总数减去第l-1颗树的左子树的数的总数。
上述说的只是没有修改的主席树,那么如果要修改节点的话,就要用树状数组维护第1到第i颗树的数的个数总和,比如说现在要把数组中第i个位置的修改为t(假设t在num个数里面的位置为vis,原来的a[i]在numge数里面的位置是vis1)那么树状数组中从第i颗树开始到第n个数的所有线段树的所有包含vis1的段全部减1,所有包含vis的段全部加1,因为主席树是一种不修改原来结构的数据结构,它每次修改一个数的时候,相当于直接添加了一颗新的树原来的树都不变,所以在求l到r第k大的数的时候,直接还是用上述的方法求出T[r] - T[l-1]再加上 S[r] - s[l-1]。
主席树建的n颗线段树并不是每建一颗树就开一颗树那么大的空间,而是重复利用之前的树,主席树一开始是建一颗叶子节点为0-num的一颗空树T[0],当你建T[1] 的时候,首先 先为T[1]建一个跟节点,如果当前要插入的数在左区间,那么为左区间建一个节点,右区间等于T[0]的右区间,然后继续往下,一直到跟节点,反正就是当前要插入左区间,就为左区间建一个节点,右区间等于上一颗树的右区间,否则 为右区间建一个节点,左区间等于上一颗树的左区间。
#include <cstdio>#include <cmath>#include <algorithm>#include <iostream>#include <cstring>#include <queue>using namespace std;const int maxn = 60005;int T[maxn]; //主席树的n个节点int S[maxn]; //树状数组维护主席树的前缀和int a[maxn],b[maxn];//离线哈希int tot;int num;int use[maxn];//求前缀和时保存当前线段树的要查询区间的根节点int lson[2500000],rson[2500000],c[2500000];//保存每颗线段树的左右节点,和当前节点数的个数int n,m;void hase(int k) //离线哈希{ sort(b,b+k); num = unique(b,b+k) - b;}int get_hase(int now) // 获取数的位置{ return lower_bound(b,b+num,now) - b;}struct Q{ int l,r,w,kind;}q[10005];//保存查询int build(int l,int r){ int root = tot++; c[root] = 0; if(l != r) { int mid = (l + r) >> 1; lson[root] = build(l,mid); rson[root] = build(mid+1,r); } return root;}//建树int insert1(int root,int pos,int val) // 创建一个新线段树,之前的继续保留下来{ int newroot = tot++; int tmp = newroot; c[newroot] = c[root] + val; int l = 0,r = num - 1; while(l < r) { int mid = (l + r) >> 1; if(mid >= pos) { lson[newroot] = tot++; rson[newroot] = rson[root]; newroot = lson[newroot]; root = lson[root]; r = mid; } else { lson[newroot] = lson[root]; rson[newroot] = tot++; newroot = rson[newroot]; root = rson[root]; l = mid + 1; } c[newroot] = c[root] + val; } return tmp;}void add(int x,int pos,int val) //更新树状数组{ while(x <= n) { S[x] = insert1(S[x],pos,val); x += x&(-x); }}int sum(int x){ int ret = 0; while(x > 0) { ret += c[lson[use[x]]]; x -= (x & (-x)); } return ret;}//计算前缀和int qurry(int ll,int rr,int pos) { int i; int rootl = T[ll]; int rootr = T[rr]; for(i = ll; i > 0 ; i-= (i & (-i))) use[i] = S[i]; for(i = rr; i > 0 ; i -= (i&(-i))) use[i] = S[i]; int l = 0,r = num - 1; while(l < r) { int mid = (l + r) >> 1; int cou = sum(rr) -sum(ll) + c[lson[rootr]] - c[lson[rootl]]; // printf("cou = %d\n",cou); if(cou < pos) { pos -= cou; for(i = ll; i > 0; i -= (i & (-i))) use[i] = rson[use[i]]; for(i = rr; i > 0; i -= (i & (-i))) use[i] = rson[use[i]]; rootl = rson[rootl]; rootr = rson[rootr]; l = mid + 1; } else { for(i = ll; i > 0; i -= i & (-i)) use[i] = lson[use[i]]; for(i = rr; i > 0; i -= i & (-i)) use[i] = lson[use[i]]; rootl = lson[rootl]; rootr = lson[rootr]; r = mid; } } return l;}int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d %d",&n,&m); int i,j; num = tot = 0; for(i = 0; i < n; i++) { scanf("%d",&a[i]); b[num++] = a[i]; } char str[10]; for(i = 0; i < m; i++) { scanf("%s %d %d",str,&q[i].l,&q[i].r); if(str[0] == 'Q') { q[i].kind = 0; scanf("%d",&q[i].w); } else { q[i].kind = 1; b[num++] = q[i].r; } } hase(num); T[0] = build(0,num-1); for(i = 1; i <= n; i++) { T[i] = insert1(T[i-1],get_hase(a[i-1]),1); } for(i = 1; i <= n; i++) S[i] = T[0]; for(i = 0; i < m; i++) { if(q[i].kind == 0) { printf("%d\n",b[qurry(q[i].l - 1,q[i].r,q[i].w)]); } else { int v = get_hase(q[i].r); add(q[i].l,get_hase(a[q[i].l-1]),-1); add(q[i].l,v,1); a[q[i].l - 1] = q[i].r; } } } return 0;}
- zoj-2112-Dynamic Rankings主席树模板
- zoj 2112 Dynamic Rankings (动态主席树)
- zoj 2112 Dynamic Rankings(主席树&动态第k大)
- ZOJ 2112 Dynamic Rankings(树状数组套主席树)
- ZOJ 2112 Dynamic Rankings [树状数组套主席树]
- ZOJ 2112-Dynamic Rankings (树状数组+主席树)
- ZOJ 2112 Dynamic Rankings(主席树套树状数组+静态主席树)
- bzoj 1901 ZOJ 2112 Dynamic Rankings [树状数组套主席树] [线段树套平衡树]
- 【主席树】 ZOJ 2112 Dynamic Rankings 区间第k小值
- ZOJ 2112 Dynamic Rankings(主席树-动态第k大)
- ZOJ 2112 Dynamic Rankings 树状数组套主席树 动态第K大
- ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)★★
- ZOJ 2112 Dynamic Rankings (主席树+单点修改,询问区间第K值)
- ZOJ 2112 Dynamic Rankings [树状数组套主席树 || CDQ分治&整体二分]
- ZOJ 2112 & BZOJ 1901 Dynamic Rankings(主席树 单点更新 区间第K大)
- ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)
- zoj 2112 Dynamic Rankings(动态第k大,树状数组套主席树)
- Zoj 2112 Dynamic Rankings
- ViewPager+Fragment问题
- CodeForces 407B DP
- SSH和EXTJS 之旅开始
- 九度OJ 题目1013:开门人和关门人
- hdoj1010Tempter of the Bone
- zoj-2112-Dynamic Rankings主席树模板
- 我多希望我学编程时,有人教我这些事!
- 调用startActivityForResult后onActivityResult立刻响应,返回当前页onActivityResult不响应的问题
- linux 删除和移动的常用快捷键
- Shell 学习15 - Shell if else 语句
- kiki's game
- 虚幻3引擎-多线程渲染机制
- HDU OJ Dividing 题目1059
- 每天一个小知识点21(拖拽效果)