HDU

按身高排序,每个人前面最高的人数有上限,如果超出上限说明impossible,

每次考虑最小的人,把他放在在当前的从左往右第k+1个空位

因为要求字典序最小,所以每次k和(上限-k)取min值。

没有修改操作,只有删除,可用线段树维护空位数量s,每次类似名次树判断一下第k个空位在哪颗子树上(原来这叫划分树

到达叶子返回位置编号并减少空位数量,push_up的时候维护一下空位数量。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+5;
struct Nd
{
    int h,k;
    void IN(){ scanf("%d%d",&h,&k); }
    bool operator < (const Nd& rh) const{
        return h < rh.h;
    }
}nd[maxn];
int N;

bool chk()
{
    sort(nd,nd+N);
    for(int i = 0,n = N-1; i <= n; i++){
        if(nd[i].k > n-i) return false;
        nd[i].k = min(nd[i].k,n-i-nd[i].k);
    }
    return true;
}

#define lo (o<<1)
#define ro (o<<1|1)
#define lsn L, M, lo
#define rsn M+1,R, ro
#define mid int M = (L+R)>>1;
#define para int L = 0, int R = N-1,int o = 1

int s[maxn<<2];
void build(para)
{
    s[o] = R-L+1;
    if(L==R) return;
    mid
    build(lsn);
    build(rsn);
}

int qk;
int qud(para)
{
    if(L==R){ s[o]--; return L; }
    mid
    int re = 0;
    if(s[lo]>=qk) re = qud(lsn);
    else { qk -= s[lo];re = qud(rsn); }
    s[o] = s[lo] + s[ro];
    return re;
}

int ans[maxn];

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    int T, ks = 0; scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        for(int i = 0; i < N; i++) nd[i].IN();
        printf("Case #%d:",++ks);
        if(!chk()) { puts(" impossible"); continue; }
        build();
        for(int i = 0; i < N; i++){
            qk = nd[i].k+1;
            ans[qud()] = nd[i].h;
        }
        for(int i = 0; i < N; i++){
            printf(" %d",ans[i]);
        }
        puts("");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jerryRey/p/4842721.html