一.题目链接:

HDU-5493

二.题目大意:

有 n 个人排队,身高各不相同.

给出每个人的身高,以及队中他前面比他高或者后面比他高的人数.

若此队伍存在,则输出最小字典序的队伍排列.

否则,输出 "impossible".

三.分析:

因为是求最小字典序,所以先对身高排序,之后再向队中加人.

假设第 i (1 ≤ i ≤ n) 个人的身高为 h,队中他前面比他高或者后面比他高的人数为 k.

则有两个位置可供他插入.

① 队中他前面比他高的人数为 k:则插入的位置应为从前往后的第 k + 1 个空位.

① 队中他后面比他高的人数为 k:则插入的位置应为从前往后的第 n - i - k + 1 个空位.

又因为要求最小字典序

所以第 i 个人所插入的位置应为 min(k+ 1, n - i - k + 1).

现在问题分解为了求第 x 个空位的索引.

有两种方法解决.

1 表示空位,0 表示已有人,

① 树状数组 + 二分:树状数组区间求和当做 check()函数,二分每个人的位置,之后再单点更新.

② 线段树:查询第 x 个空位的下标,之后再单点更新.

现在考虑什么情况是有矛盾的.

易得:第 i 个人前面的空位不足 k 且 后面的空位也不足 k.

即:k + i > n.

四.代码实现:

①树状数组 + 二分

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long int
using namespace std;

const int M = (int)1e5;
const int inf = 0x3f3f3f3f;

struct node
{
    int k;
    int h;
}s[M + 5];

int n;
int h[M + 5];
int c[M + 5];

bool cmp(node a, node b)
{
    return a.h < b.h;
}

int lowbit(int x)
{
    return x & (-x);
}

void update(int x, int v)
{
    for(int i = x; i <= n; i += lowbit(i))
        c[i] += v;
}

int sum(int x)
{
    int ans = 0;
    for(int i = x; i > 0; i -= lowbit(i))
        ans += c[i];
    return ans;
}

int binary1(int i)
{
    int l = 1;
    int r = n;
    while(l < r)
    {
        int mid = (l + r) >> 1;
        if(sum(mid) < s[i].k + 1)
            l = mid + 1;
        else
            r = mid;
    }
    return r;
}

int binary2(int i)
{
    int l = 1;
    int r = n;
    while(l < r)
    {
        int mid = (l + r + 1) >> 1;
        if(sum(n) - sum(mid - 1) < s[i].k + 1)
            r = mid - 1;
        else
            l = mid;
    }
    return r;
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ++ca)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d %d", &s[i].h, &s[i].k);
        sort(s + 1, s + n + 1, cmp);
        memset(c, 0, sizeof(c));
        for(int i = 1; i <= n; ++i)
            update(i, 1);
        bool flag = 1;
        for(int i = 1; i <= n; ++i)
        {
            if(i + s[i].k > n)
            {
                flag = 0;
                break;
            }
            int pos = min(binary1(i), binary2(i));
            h[pos] = s[i].h;
            update(pos, -1);
        }
        printf("Case #%d: ", ca);
        if(flag)
        {
            for(int i = 1; i <= n; ++i)
                printf("%d%c", h[i], i == n ? '\n' : ' ');
        }
        else
            printf("impossible\n");
    }
    return 0;
}

② 线段树

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long int
using namespace std;

const int M = (int)1e5;
const int inf = 0x3f3f3f3f;

int n;

struct node1
{
    int h;
    int k;
} s[M + 5];

int height[M + 5];
int tree[M * 4 + 5];

bool cmp(node1 a, node1 b)
{
    return a.h < b.h;
}

void push_up(int k)
{
    tree[k] = tree[lc] + tree[rc];
}

void build(int k, int l, int r)
{
    if(l == r)
    {
        tree[k] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
    push_up(k);
}

int query(int k, int l, int r, int a, int b)
{
    if(l >= a && r <= b)
        return tree[k];
    int mid = (l + r) >> 1;
    int ans = 0;
    if(a <= mid)
        ans += query(lc, l, mid, a, b);
    if(mid < b)
        ans += query(rc, mid + 1, r, a, b);
    return ans;
}

void update(int k, int l, int r, int num, int h)
{
    if(l == r)
    {
        tree[k] = 0;
        height[l] = h;
        return;
    }
    int mid = (l + r) >> 1;
    if(num <= tree[lc])
        update(lc, l, mid, num, h);
    else
        update(rc, mid + 1, r, num - tree[lc], h);
    push_up(k);
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ++ca)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d %d", &s[i].h, &s[i].k);
        build(1, 1, n);
        sort(s + 1, s + n + 1, cmp);
        bool flag = 1;
        for(int i = 1; i <= n; ++i)
        {
            if(i + s[i].k > n)
            {
                flag = 0;
                break;
            }
            update(1, 1, n, min(s[i].k + 1, n - i - s[i].k + 1), s[i].h);
        }
        printf("Case #%d: ", ca);
        if(flag)
        {
            for(int i = 1; i <= n; ++i)
                printf("%d%c", height[i], i == n ? '\n' : ' ');
        }
        else
            printf("impossible\n");
    }
    return 0;
}