【ZOJ2112】【整体二分+树状数组】带修改区间第k大
2015-03-15 15:12
495 查看
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
, 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
【分析】
裸题,不说了。
按照这种方法的话,离线的带插入修改区间第K大也应该可以做了。
不过这题的经典作法是树状数组上套可持久化线段树,不过这样空间消耗会很大。
可能要用动态开点?
转一个用块状链表的:http://www.cnblogs.com/zhj5chengfeng/archive/2013/08/19/3268162.html
View Code
, 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
【分析】
裸题,不说了。
按照这种方法的话,离线的带插入修改区间第K大也应该可以做了。
不过这题的经典作法是树状数组上套可持久化线段树,不过这样空间消耗会很大。
可能要用动态开点?
转一个用块状链表的:http://www.cnblogs.com/zhj5chengfeng/archive/2013/08/19/3268162.html
/* 宋代晏殊 《蝶恋花·槛菊愁烟兰泣露》 槛菊愁烟兰泣露。罗幕轻寒,燕子双飞去。明月不谙离恨苦。斜光到晓穿朱户。 昨夜西风凋碧树。独上高楼,望尽天涯路。欲寄彩笺兼尺素。山长水阔知何处。 */ #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <utility> #include <iomanip> #include <string> #include <cmath> #include <queue> #include <assert.h> #include <map> #include <ctime> #include <cstdlib> #include <stack> #define LOCAL const int INF = 1000000000; const int MAXN = 300000 + 10; using namespace std; struct QUERY{ int x, y; int k, s, type, cur;//cur用来记录前面的值 }q[MAXN], q1[MAXN], q2[MAXN]; int Ans[MAXN]; int tmp[MAXN], c[MAXN]; int n, m, num, cnt; int data[MAXN]; inline int lowbit(int x){return x&-x;} void add(int x, int val){ while (x <= n){ c[x] += val; x += lowbit(x); } return; } int sum(int x){ int cnt = 0; while (x > 0){ cnt += c[x]; x -= lowbit(x); } return cnt; } //整体二分 void solve(int l, int r, int L, int R){ //这两个都是结束条件 if (l > r) return; if (L == R){//更新答案 for (int i = l; i <= r; i++) if (q[i].type == 3) Ans[q[i].s] = L; return; } int mid = (L + R) >> 1; for (int i = l; i <= r; i++){ if (q[i].type == 1 && q[i].y <= mid) add(q[i].x, 1); else if (q[i].type == 2 && q[i].y <= mid) add(q[i].x, -1); else if (q[i].type == 3) tmp[i] = sum(q[i].y) - sum(q[i].x - 1); } //更新完了就要清除标记了 for (int i = l; i <= r; i++){ if (q[i].type == 1 && q[i].y <= mid) add(q[i].x, -1); else if (q[i].type == 2 && q[i].y <= mid) add(q[i].x, 1); } int l1 = 0, l2 = 0; for (int i = l; i <= r; i++){ if (q[i].type == 3){ //不用id就直接改 if (q[i].cur + tmp[i] > q[i].k - 1) q1[++l1] = q[i]; else { q[i].cur += tmp[i]; q2[++l2] = q[i]; } }else{ if (q[i].y <= mid) q1[++l1] = q[i]; else q2[++l2] = q[i]; } } for (int i = 1; i <= l1; i++) q[i + l - 1] = q1[i]; for (int i = 1; i <= l2; i++) q[i + l1 + l - 1] = q2[i]; solve(l, l + l1 - 1, L, mid); solve(l + l1, r, mid + 1, R); } void init(){ memset(c, 0, sizeof(c)); cnt = num = 0;//指针初始化,num记录总的操作数量 scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++){ num++; scanf("%d", &data[i]); q[num].x = i;q[num].type = 1;//1代表插入 q[num].s = 0;q[num].y = data[i];//没有用y就当val用 } for (int i = 1; i <= m; i++){ char str[2]; num++; scanf("%s", str); if (str[0] == 'Q'){ int l, r, k; scanf("%d%d%d", &l, &r, &k); q[num].x = l;q[num].y = r; q[num].type = 3; q[num].s = ++cnt; q[num].k = k; }else{ int l, x; scanf("%d%d", &l, &x); q[num].x = l;q[num].y = data[l];//2为删除 q[num].type = 2;q[num].s = 0; q[++num].x = l; q[num].y = x;//删除后插入 q[num].type = 1; q[num].s = 0; data[l] = x;//注意这里一定要改,不然会影响到后面的更新 } } for (int i = 1; i <= num; i++) q[i].cur = 0; } int main(){ int T; scanf("%d", &T); while (T--){ init(); solve(1, num, 0, INF); for (int i = 1; i <= cnt; i++) printf("%d\n", Ans[i]); } return 0; }
View Code
相关文章推荐
- ZOJ 2112 Dynamic Rankings(动态求区间第k大+整体二分)
- ZOJ 2112 Dynamic Rankings 树状数组套主席树 单点修改求动态区间第K大
- ZOJ 2112 动态区间第K大(二分答案+线段树套Treap)
- hdu 5412 CRB and Queries(动态区间第k大值,区间能修改)(整体二分,树状数组套平衡树,线段树套treap)
- 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改
- bzoj 1901: Zju2112 Dynamic Rankings(带修改的区间第k大,树状数组+主席树)
- 【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询
- zoj 2112 Dynamic Rankings 带修改区间第k大的几种解法
- ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】
- ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】
- 【BZOJ 3110】 [Zjoi2013]K大数查询 整体二分+树状数组区间修改
- 【HDU5412】CRB and Queries-整体二分:带修改区间第K小
- zoj2112 Dynamic Rankings 单点修改区间第k小
- ZOJ 2112 Dynamic Rankings (动态区间第K大) (线段树套SBT+二分)
- ZOJ 2112 Dynamic Rankings (主席树+单点修改,询问区间第K值)
- 【XSY2720】区间第k小 整体二分 可持久化线段树
- 【主席树】 ZOJ 2112 Dynamic Rankings 区间第k小值
- ZOJ 2112 动态第k大 主席树+树状数组
- 51nod 第K大区间2(二分+树状数组)
- ZOJ 2112 Dynamic Rankings 动态区间第k大 分块