hdu5493(线段树,离线操作,点修改,区间查询)

题目链接:点击打开链接

//hdu5493
//题目大意:给n个人排队,每个人都有身高hi,并且只记得前面或者后面有ki个人比他高,要求身高字典序最小
//大概思路:
//          离线操作;
//          对每个人都相当于有两个位置;
//          对身高排序,给身高矮的人尽量选靠前的位置;
//          相当于找空位,用线段树进行点修改,区间查询


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define N 100020

using namespace std;

struct stu
{
    int h, k;
}s[N];

int sum[N<< 2];
int ans[N], n;

bool cmps(stu a, stu b)
{
    return a.h< b.h;
}

void pushup(int k) { sum[k]= sum[k<< 1]+ sum[k<< 1| 1]; }

void build(int l, int r, int k)
{
    if(l== r) { sum[k]= 1; return; }
    int m= (l+ r)>> 1;
    build(l, m, k<< 1);
    build(m+ 1, r, k<< 1| 1);
    pushup(k);
}

int query(int t, int l, int r, int k)
{
    if(sum[k]< t) return -1;
    if(l== r) return l;
    int m= (l+ r)>> 1, anss;
    if(sum[k<< 1]>= t) anss= query(t, l, m, k<< 1);
    else anss= query(t- sum[k<< 1], m+ 1, r, k<< 1| 1);
    return anss;
}

void update(int p, int l, int r, int k)
{
    if(l== r) { sum[k]= 0; return; }
    int m= (l+ r)>> 1;
    if(p<= m) update(p, l, m, k<< 1);
    else update(p, m+ 1, r, k<< 1| 1);
    pushup(k);
}

int main()
{
    int T; cin >> T;
    for(int TT= 1; TT<= T; TT++)
    {
        scanf("%d", &n);
        memset(sum, 0, sizeof(sum));
        for(int i= 1; i<= n; i++) scanf("%d%d", &s[i].h, &s[i].k);
        sort(s+ 1, s+ n+ 1, cmps);
        build(1, n, 1);
        int flag= 0;
        for(int i= 1; i<= n; i++)
        {
            int pos1= query(s[i].k+ 1, 1, n, 1), pos2= query(n- s[i].k- i+ 1, 1, n, 1);
            int p= min(pos1, pos2);
            if(p== -1) { flag= 1; break; } else ans[p]= s[i].h;
            update(p, 1, n, 1);
        }
        printf("Case #%d: ", TT);
        if(flag) printf("impossible\n");
        else
        {
            printf("%d", ans[1]);
            for(int i= 2; i<= n; i++) printf(" %d", ans[i]);
            printf("\n");
        }
    }
    return 0;
}


你可能感兴趣的:(线段树,hdu)