首页 > 代码库 > POJ 2104:K-th Number(整体二分)
POJ 2104:K-th Number(整体二分)
http://poj.org/problem?id=2104
题意:给出n个数和m个询问求区间第K小。
思路:以前用主席树做过,这次学整体二分来做。整体二分在yr大佬的指点下,终于大概懂了点了。对于二分能够解决的询问,如果有多个,那么如果支持离线处理的话,那么就可以使用整体二分了。
在这题二分可行的答案,根据这个答案,把询问操作丢在左右两个队列里面分别递归继续按这样处理。注释里写的很详细。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cstdio> 5 #include <cmath> 6 #include <algorithm> 7 #include <ctime> 8 #include <vector> 9 #include <queue> 10 #include <map> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int N = 150011; 15 const int INF = 0x3f3f3f3f; 16 struct P { 17 int type, l, r, val, id; 18 } q[N], lq[N], rq[N]; 19 int ans[N], bit[N], sum[N], gap; 20 21 int lowbit(int x) { return x & (-x); } 22 void update(int x, int w) { while(x <= gap) bit[x] += w, x += lowbit(x); } 23 int query(int x) { int ans = 0; while(x) ans += bit[x], x -= lowbit(x); return ans; } 24 25 void Solve(int lask, int rask, int l, int r) { // 整体二分答案,判断答案是否可行 26 if(rask < lask || r < l) return ; 27 if(l == r) // 如果找到合适的答案了,那么在这段区间的查询的全部答案都是属于它 28 { for(int i = lask; i <= rask; i++) if(q[i].type == 2) ans[q[i].id] = l; return ; } 29 int mid = (l + r) >> 1, lcnt = 0, rcnt = 0; 30 for(int i = lask; i <= rask; i++) { // 遍历这段询问 31 if(q[i].type == 1) { // 如果是插入 32 if(q[i].val <= mid) { // 因为查询的是第k小,那么就是升序排列的第k个数字 33 lq[++lcnt] = q[i]; // 如果插入的数比当前枚举的答案小,那么符合条件,在树状数组上插入并丢入左队列 34 update(q[i].id, 1); 35 } else rq[++rcnt] = q[i]; // 插入的数比当前枚举的答案大,对当前枚举的答案无影响,丢入右队列 36 } else { // 如果是询问 37 int num = query(q[i].r) - query(q[i].l - 1); // 那么查询这段区间有多少个数 38 if(q[i].val <= num) lq[++lcnt] = q[i]; // 如果这段区间的数字比当前查询的k多,那么说明答案在左边 39 else { // 否则在右边,在右边的话还要减去左边拥有的 40 q[i].val -= num; 41 rq[++rcnt] = q[i]; 42 } 43 } 44 } 45 for(int i = lask; i <= rask; i++) if(q[i].type == 1 && q[i].val <= mid) update(q[i].id, -1); 46 for(int i = 1; i <= lcnt; i++) q[i+lask-1] = lq[i]; // 重新构造 47 for(int i = 1; i <= rcnt; i++) q[i+lask+lcnt-1] = rq[i]; 48 Solve(lask, lask + lcnt - 1, l, mid); // 分两边递归处理 49 Solve(lask + lcnt, rask, mid + 1, r); 50 } 51 52 int main() { 53 int n, m, a, b, c; 54 scanf("%d%d", &n, &m); gap = n; 55 for(int i = 1; i <= n; i++) { 56 scanf("%d", &a); 57 q[i] = (P){1, 1, 1, a, i}; 58 } 59 for(int i = 1; i <= m; i++) { 60 scanf("%d%d%d", &a, &b, &c); 61 q[n+i] = (P){2, a, b, c, i}; 62 } 63 Solve(1, n + m, -INF, INF); 64 for(int i = 1; i <= m; i++) printf("%d\n", ans[i]); 65 return 0; 66 }
POJ 2104:K-th Number(整体二分)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。