ZOJ 2112 Dynamic Rankings(主席树の动态kth)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112

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.

题目大意:给n个数,有m个操作。修改某个数,或者询问一段区间的第k小值。

思路:首先要知道没有修改操作的区间第k大怎么用出席树写:POJ 2104 K-th Number(主席树——附讲解)

至于动态kth的解法可以去看CLJ的《可持久化数据结构研究》(反正我是看这个才懂的),然后在网上查一些资料,YY一下就可以了。

这里写的是树状数组套线段树+可持久化线段树的做法(因为内存不够用)。

简单的讲就是通过树状数组求和,维护前k个线段树的和。时间复杂度为O(nlogn+m(logn)^2)

另参考资料(里面有好几个link :)):http://www.cnblogs.com/kuangbin/p/3308118.html

PS:ZOJ的指针似乎不是4个字节的。这里用指针就要MLE了(代码本来不是这么丑的啊T_T)。

代码(130MS):

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <cstring>
  5 using namespace std;
  6 typedef long long LL;
  7
  8 const int MAXN = 50010;
  9 const int MAXM = 10010;
 10 const int MAXT = MAXM * 15 * 16;
 11
 12 struct Query {
 13     char op;
 14     int i, j, k;
 15     void read() {
 16         scanf(" %c", &op);
 17         if(op == ‘Q‘) scanf("%d%d%d", &i, &j, &k);
 18         else scanf("%d%d", &i, &k);
 19     }
 20 } query[MAXM];
 21 int a[MAXN];
 22 int n, m, T;
 23 //hashmap
 24 int arr[MAXN + MAXM], total;
 25
 26 void buildHash() {
 27     total = 0;
 28     for(int i = 1; i <= n; ++i) arr[total++] = a[i];
 29     for(int i = 1; i <= m; ++i)
 30         if(query[i].op == ‘C‘) arr[total++] = query[i].k;
 31     sort(arr, arr + total);
 32     total = unique(arr, arr + total) - arr;
 33 }
 34
 35 int hash(int x) {
 36     return lower_bound(arr, arr + total, x) - arr;
 37 }
 38 //Chairman tree
 39 struct Node {
 40     int lson, rson, sum;
 41     void clear() {
 42         lson = rson = sum = 0;
 43     }
 44 } tree[MAXT];
 45 int root[MAXN];
 46 int tcnt;
 47
 48 void insert(int& rt, int l, int r, int pos) {
 49     tree[tcnt] = tree[rt]; rt = tcnt++;
 50     tree[rt].sum++;
 51     if(l < r) {
 52         int mid = (l + r) >> 1;
 53         if(pos <= mid) insert(tree[rt].lson, l, mid, pos);
 54         else insert(tree[rt].rson, mid + 1, r, pos);
 55     }
 56 }
 57
 58 void buildTree() {
 59     tcnt = 1;
 60     for(int i = 1; i <= n; ++i) {
 61         root[i] = root[i - 1];
 62         insert(root[i], 0, total - 1, hash(a[i]));
 63     }
 64 }
 65 //Binary Indexed Trees
 66 int root2[MAXN];
 67 int roota[50], rootb[50];
 68 int cnta, cntb;
 69
 70 void initBIT() {
 71     for(int i = 1; i <= n; ++i) root2[i] = 0;
 72 }
 73
 74 inline int lowbit(int x) {
 75     return x & -x;
 76 }
 77
 78 void insert(int& rt, int l, int r, int pos, int val) {
 79     if(rt == 0) tree[rt = tcnt++].clear();
 80     if(l == r) {
 81         tree[rt].sum += val;
 82     } else {
 83         int mid = (l + r) >> 1;
 84         if(pos <= mid) insert(tree[rt].lson, l, mid, pos, val);
 85         else insert(tree[rt].rson, mid + 1, r, pos, val);
 86         tree[rt].sum = tree[tree[rt].lson].sum + tree[tree[rt].rson].sum;
 87     }
 88 }
 89
 90 int kth(int ra, int rb, int l, int r, int k) {
 91     if(l == r) {
 92         return l;
 93     } else {
 94         int sum = tree[tree[rb].lson].sum - tree[tree[ra].lson].sum, mid = (l + r) >> 1;
 95         for(int i = 0; i < cntb; ++i) sum += tree[tree[rootb[i]].lson].sum;
 96         for(int i = 0; i < cnta; ++i) sum -= tree[tree[roota[i]].lson].sum;
 97         if(sum >= k) {
 98             for(int i = 0; i < cntb; ++i) rootb[i] = tree[rootb[i]].lson;
 99             for(int i = 0; i < cnta; ++i) roota[i] = tree[roota[i]].lson;
100             return kth(tree[ra].lson, tree[rb].lson, l, mid, k);
101         } else {
102             for(int i = 0; i < cntb; ++i) rootb[i] = tree[rootb[i]].rson;
103             for(int i = 0; i < cnta; ++i) roota[i] = tree[roota[i]].rson;
104             return kth(tree[ra].rson, tree[rb].rson, mid + 1, r, k - sum);
105         }
106     }
107 }
108 //Main operation
109 void modify(int k, int val) {
110     int x = hash(a[k]), y = hash(val);
111     a[k] = val;
112     while(k <= n) {
113         insert(root2[k], 0, total - 1, x, -1);
114         insert(root2[k], 0, total - 1, y, 1);
115         k += lowbit(k);
116     }
117 }
118
119 int kth(int l, int r, int k) {
120     cnta = cntb = 0;
121     for(int i = l - 1; i; i -= lowbit(i)) roota[cnta++] = root2[i];
122     for(int i = r; i; i -= lowbit(i)) rootb[cntb++] = root2[i];
123     return kth(root[l - 1], root[r], 0, total - 1, k);
124 }
125
126 int main() {
127     scanf("%d", &T);
128     while(T--) {
129         scanf("%d%d", &n, &m);
130         for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
131         for(int i = 1; i <= m; ++i) query[i].read();
132         buildHash();
133         buildTree();
134         initBIT();
135         for(int i = 1; i <= m; ++i) {
136             if(query[i].op == ‘Q‘) printf("%d\n", arr[kth(query[i].i, query[i].j, query[i].k)]);
137             else modify(query[i].i, query[i].k);
138         }
139     }
140 }

ZOJ 2112 Dynamic Rankings(主席树の动态kth),布布扣,bubuko.com

时间: 2024-10-13 11:59:34

ZOJ 2112 Dynamic Rankings(主席树の动态kth)的相关文章

zoj 2112 Dynamic Rankings(主席树&amp;动态第k大)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB 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

ZOJ -2112 Dynamic Rankings 主席树 待修改的区间第K大

Dynamic Rankings 带修改的区间第K大其实就是先和静态区间第K大的操作一样.先建立一颗主席树, 然后再在树状数组的每一个节点开线段树(其实也是主席树,共用节点), 每次修改的时候都按照树状数组的方式去修改,并且修改那些地方.查询的时候就是查询原主席树+树状数组的值. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r&quo

zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树

pass 首先,个人觉得把这个数据结构理解成树状数组套主席树是十分不严谨的.主席树的本质是可持久化权值线段树与前缀和思想的结合.而动态主席树是可持久化权值线段树与树状数组思想的结合.并非树套树般的泾渭分明的叠加. 其次,大概讲下对动态主席树的理解.我们静态主席树中,第i个版本维护的是[1,i]的权值线段树,我们利用前缀和的思想,通过y的版本-x的版本得到[x,y]的权值线段树,从而剥离出一颗对应区间的权值线段树.我们考虑在这个情况下,如果需要修改第a[i]的值,那么从i,i+1,i+2.....

zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 Description The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query l

ZOJ 2112 Dynamic Rankings(树状数组+主席树)

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],

ZOJ 2112 Dynamic Rankings(主席树套树状数组+静态主席树)

题意:给定一个区间,求这个区间第k大的数,支持单点修改. 思路:主席树真是个神奇的东西.........速度很快但是也有一个问题就是占用内存的很大,一般来说支持单点修改的主席树套树状数组空间复杂度为O(n*logn*logn), 如果查询较少的话,可以初始的时候用一颗静态主席树,这样空间复杂度可以降为O(n*logn+q*logn*logn),勉强可以过zoj这道题. 这道题看了好久好久才懂...网上题解一般就几句话.......下面是自己的一些理解. 首先静态主席树这个东西其实比较好懂,就是对

zoj 2112 Dynamic Rankings(树状数组套主席树)

题意:对于一段区间,每次求[l,r]的第k大,存在单点修改操作: 思路: 学习主席树参考: http://blog.csdn.net/wjf_wzzc/article/details/24560117(各种形式) http://blog.csdn.net/bossup/article/details/31921235(推荐) http://blog.csdn.net/xiaofengcanyuexj/article/details/25553521?utm_source=tuicool(图解)

ZOJ 2112 Dynamic Rankings(带修改的区间第K大,分块+二分搜索+二分答案)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB 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

bzoj 1901: Zju2112 Dynamic Rankings -- 主席树,树状数组,哈希

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改 变后的a继续回答上面的问题. Input 第一行有两个正整数n(1≤