zoukankan      html  css  js  c++  java
  • 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
    ", ans[i]);
    65     return 0;
    66 }
  • 相关阅读:
    js基础之变量作用域和es6解构赋值
    js基础之函数的定义和调用
    js基础之引用数据类型
    js基础之基本数据类型
    js基础之变量声明提升
    浏览器渲染页面
    flex布局
    web前端性能优化
    动态修改docker容器环境变量env
    蓝鲸前端框架
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6286065.html
Copyright © 2011-2022 走看看