hdu5493 queue 贪心+离线+线段树统计个数

题目真不难。。。

按高度从小到大加到线段树统计下次数求第k大就可以了,由于要字典序最小,所以每次把当前的尽量往前加,有k个人比它高,就两个位置,k+1和n-k,贪心取最靠前的就行了。

水题!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define key_val ch[ch[rt[i]][1]][0]
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;
struct Node
{
    int h,k;
    friend bool operator<(Node A,Node B)
    {
        return A.h<B.h;
    }
};Node a[maxn];
int ans[maxn];
int cnt[maxn<<2];

void push_up(int rt)
{
    cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
}

void build(int l,int r,int rt)
{
    if(l==r){
        cnt[rt]=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}

int find_kth(int k,int l,int r,int rt)
{
    if(l==r){
        cnt[rt]=0;
        return l;
    }
    int m=(l+r)>>1;
    int res=0;
    if(k<=cnt[rt<<1]) res=find_kth(k,lson);
    else res=find_kth(k-cnt[rt<<1],rson);
    push_up(rt);
    return res;
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int T;cin>>T;
    REP(casen,1,T){
        scanf("%d",&n);
        REP(i,1,n) scanf("%d%d",&a[i].h,&a[i].k);
        sort(a+1,a+n+1);
        build(1,n,1);
        bool flag=1;
        int rk,pos;
        REP(i,1,n){
            if(a[i].k+1>cnt[1]){
                flag=0;break;
            }
            rk=min(a[i].k+1,cnt[1]-a[i].k);
            pos=find_kth(rk,1,n,1);
            ans[pos]=a[i].h;
        }
        printf("Case #%d:",casen);
        if(!flag) puts(" impossible");
        else{
            REP(i,1,n) printf(" %d",ans[i]);
            puts("");
        }
    }
    return 0;
}
View Code

 

你可能感兴趣的:(hdu5493 queue 贪心+离线+线段树统计个数)