zoukankan      html  css  js  c++  java
  • G

    G - Queue

     HDU - 5493 

    题目大意:给你n个人的身高和这个人前面或者后面有多少个比他高的人,让你还原这个序列,按字典序输出。

    题解:

    首先按高度排序。

    设每个人在其前面有k个人,设比这个人高有x个人,所以k=min(k,x-k),求出每一个人在他前面比他高的人的数量。

    然后用线段树来维护一段区间的空位,因为对于每一个人来说比他高的人肯定都是出现在他后面,所以这个就说明它前面要空出几个空位。

    但是线段树可以维护一段区间的空位,没办法准确找出我需要空位为一个准确的数的位置。

    这个就可以二分答案。

    要注意几个细节,如果用线段树的话,这个 l 不要从1开始,不然会 T,

    然后就是二分这个地方要注意写法,我之前一种写法错了。

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    const int maxn = 1e5 + 10;
    int ans[maxn];
    int n;
    struct node {
        int h, k;
        node(int h = 0, int k = 0) :h(h), k(k) {}
    }ex[maxn];
    
    bool cmp(node a, node b) {
        return a.h < b.h;
    }
    int sum[maxn * 4];
    void push_up(int id) {
        sum[id] = sum[id << 1] + sum[id << 1 | 1];
    }
    
    void build(int id, int l, int r) {
        sum[id] = 0;
        if (l == r) return;
        int mid = (l + r) >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
    }
    
    void update(int id, int l, int r, int pos) {
        if (l == r) {
            sum[id] = 1;
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) update(id << 1, l, mid, pos);
        else update(id << 1 | 1, mid + 1, r, pos);
        push_up(id);
    }
    
    int query(int id, int l, int r, int x, int y) {
        if (x <= l && y >= r) return r - l + 1 - sum[id];
        int mid = (l + r) >> 1;
        int ans = 0;
        if (x <= mid) ans += query(id << 1, l, mid, x, y);
        if (y > mid) ans += query(id << 1 | 1, mid + 1, r, x, y);
        return ans;
    }
    
    
    int main() {
        int t, cnt = 0;
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                int h, k;
                scanf("%d%d", &h, &k);
                ex[i] = node(h, k);
            }
            int flag = 0;
            sort(ex + 1, ex + 1 + n, cmp);
            for (int i = 1; i <= n; i++) {
                if (n - i - ex[i].k < 0) flag = 1;
                ex[i].k = min(ex[i].k, n - i - ex[i].k);
            }
            if (flag) {
                printf("Case #%d: impossible
    ", ++cnt);
                continue;
            }
            build(1, 1, n);
            for (int i = 1; i <= n; i++) {
                int l = ex[i].k + 1, r = n;
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    int res = query(1, 1, n, 1, mid);
                    if (res > ex[i].k) r = mid - 1;
                    else l = mid + 1;
                }
                ans[r + 1] = ex[i].h;
                update(1, 1, n, r + 1);
            }
            printf("Case #%d:", ++cnt);
            for (int i = 1; i <= n; i++) printf(" %d", ans[i]);
            printf("
    ");
        }
        return 0;
    }
    线段树
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    const int maxn = 1e5 + 10;
    int ans[maxn];
    int n;
    struct node {
        int h, k;
        node(int h = 0, int k = 0) :h(h), k(k) {}
    }ex[maxn];
    
    bool cmp(node a, node b) {
        return a.h < b.h;
    }
    int sum[maxn];
    
    int lowbit(int x)
    {
        return x & (-x);
    }
    
    void update(int i,int k)
    {
        while(i<n)
        {
            sum[i] += k;
            i += lowbit(i);
        }
    }
    
    int getsum(int x)
    {
        int res = 0;
        while(x>0)
        {
            res += sum[x];
            x -= lowbit(x);
        }
        return res;
    }
    
    
    int main() {
        int t, cnt = 0;
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                sum[i] = 0;
                int h, k;
                scanf("%d%d", &h, &k);
                ex[i] = node(h, k);
            }
            int flag = 0;
            sort(ex + 1, ex + 1 + n, cmp);
            for (int i = 1; i <= n; i++) {
                if (n - i - ex[i].k < 0) {
                    flag = 1;
                    break;
                }
                ex[i].k = min(ex[i].k, n - i - ex[i].k);
            }
            if (flag) {
                printf("Case #%d: impossible
    ", ++cnt);
                continue;
            }
            for (int i = 1; i <= n; i++) {
                int l = ex[i].k + 1, r = n;
                int num = ex[i].k + 1;
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    int res = mid - getsum(mid), e = getsum(mid) - getsum(mid - 1);
                    // if (res == num && e == 0) {
                    //     ans[mid] = ex[i].h;
                    //     update(mid, 1);
                    //     flag1 = 1;
                    //     break;
                    // }
                    if (res >= num) r = mid - 1;
                    else l = mid + 1;
                }
                ans[r + 1] = ex[i].h;
                update(r + 1, 1);
            }
            printf("Case #%d:", ++cnt);
            for (int i = 1; i <= n; i++) printf(" %d", ans[i]);
            printf("
    ");
        }
        return 0;
    }
    树状数组
  • 相关阅读:
    whereis which type find
    souce and bash 的区别
    systemctl daemon-reload
    linux /etc/profile bashrc bash_profile
    ulimt 和 sysctl
    MySQL 问题总结
    asyncio
    Linux 中 MySQL 操作
    总结一波 Redis 面试题
    os 模块 和 re 模块
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/11358870.html
Copyright © 2011-2022 走看看