HDU 5412 CRB and Queries 整体二分

来源:互联网 发布:炫舞卡坐骑软件 编辑:程序博客网 时间:2024/06/11 02:21

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=5412

题意:

给定一个长度为n的序列,有以下两种操作:1 x y k,求区间[x,y]中的第k小数,2 x y,把位置x的元素替换为y。

思路:

用的整体二分。谈一下自己对整体二分的理解(如有错误请谅解):整体二分总体来说是分治,然后用二分枚举一个值,在分治的时候用这个枚举值来划分左右子区间。像求第k小数,二分枚举一个值,对于序列中的元素,如果小于等于枚举值,就划分到左子区间,否则就划分到右子区间;对于询问,判断当前枚举值时,统计询问区间中元素在左子区间中出现的个数,如果大于等于k的话,答案肯定在左子区间中,把这个查询也划分到左子区间中,否则的话,划分到右子区间中,可以发现右子区间的枚举值肯定是比当前枚举值大,意味着左子区间中的元素对于右子区间中询问贡献是固定的,可以直接减去这个贡献,然后再在右子区间中查找。另外这个题有修改操作,可以把修改看做删除原位置上的数,然后在原位置上再插入一个数,分解为两步,按顺序加入到操作队列中,对于序列初始值,可以看做只插入不删除,然后按静态的做就好了,因为操作队列是按时间序排的,这样一定是正确的。
这个题与ZOJ2112基本是一样的,不过那道题数据范围要小很多,特别是查询少了很多!于是那个题我用分块水了过去,这道题用分块就TLE了,毕竟查询太多了。以后查询多的不能用分块,毕竟这玩意其实就是个优美的暴力,查询少的可以尝试一下

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N = 100000 + 10, M = 100000 + 10;struct BIT{    int n, b[N];    void init(int _n)    {        n = _n;        memset(b, 0, sizeof b);    }    void add(int i, int x)    {        while(i <= n) b[i] += x, i += i & -i;    }    int sum(int i)    {        int ans = 0;        while(i > 0) ans += b[i], i -= i & -i;        return ans;    }} bit;struct node{    int x, y, k, id, type;    void init(int _x, int _y, int _k, int _id, int _type)    {        x = _x, y = _y, k = _k, id = _id, type = _type;    }} q[N+M*2], ql[N+M*2], qr[N+M*2];int a[N], ans[M];void divide_conquer(int st, int en, ll l, ll r){    if(st > en) return;    if(l == r)//此时答案确定    {        for(int i = st; i <= en; i++)            if(q[i].type == 2) ans[q[i].id] = l;        return;    }    ll mid = (l + r) >> 1;    int kl = 0, kr = 0;    for(int i = st; i <= en; i++)    {        if(q[i].type == 1)//序列中的元素        {            if(q[i].x <= mid)            {                ql[kl++] = q[i];                bit.add(q[i].id, q[i].y);//树状数组统计            }            else qr[kr++] = q[i];        }        else//查询操作        {            int num = bit.sum(q[i].y) - bit.sum(q[i].x - 1);            if(num >= q[i].k) ql[kl++] = q[i];            else            {                q[i].k -= num;                qr[kr++] = q[i];            }        }    }    for(int i = 0; i < kl; i++)//还原树状数组        if(ql[i].type == 1) bit.add(ql[i].id, -ql[i].y);    for(int i = 0; i < kl; i++) q[st+i] = ql[i];    for(int i = 0; i < kr; i++) q[st+kl+i] = qr[i];    divide_conquer(st, st + kl - 1, l, mid);    divide_conquer(st + kl, en, mid + 1, r);}int main(){    int n, m;    while(~ scanf("%d", &n))    {        bit.init(n);        int tot = 0, x, y, k;        char ch;        for(int i = 1; i <= n; i++)        {            scanf("%d", &a[i]);            q[++tot].init(a[i], 1, 0, i, 1);        }        scanf("%d", &m);        for(int i = 1; i <= m; i++)        {            scanf(" %c%d%d", &ch, &x, &y);            if(ch == '2')            {                scanf("%d", &k);                q[++tot].init(x, y, k, i, 2);            }            else            {                q[++tot].init(a[x], -1, 0, x, 1);                q[++tot].init(y, 1, 0, x, 1);                a[x] = y;            }        }        memset(ans, -1, sizeof ans);        divide_conquer(1, tot, INT_MIN, INT_MAX);        for(int i = 1; i <= m; i++)            if(ans[i] != -1) printf("%d\n", ans[i]);    }    return 0;}
阅读全文
0 0
原创粉丝点击