题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5493
解题思路:
一道线段树的题目,因为是前面或者后面有k个比自己高的人,所以我们应该按照由身高从小到大排序,这样前面的人对后面的人就没有什么影响。我们线段树中存的是每一段有多少空位置。这样每次如果根节点的空位置小于k,那么很明显没办法放,同样因为前面对后面的没有什么影响,我只需要找到k和n-k-i中较小的,如果这个值小于0,那么则没有办法继续插入。因为满足字典序最小,因此往最前面位置插入就可以了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100005;
struct Node
{
int h,k;
bool operator < (const Node &rhs) const
{
return h < rhs.h;
}
}p[maxn];
struct Seg
{
int l,r,sum;
}tree[maxn<<2];
int n,res[maxn];
void build(int rt,int l,int r)
{
tree[rt].l = l, tree[rt].r = r;
tree[rt].sum = r - l + 1;
if(l == r) return;
int mid = (l + r) >> 1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
}
void update(int rt,int k,int val)
{
if(tree[rt].l == tree[rt].r)
{
res[tree[rt].l] = val;
tree[rt].sum = 0;
return;
}
if(tree[rt<<1].sum >= k) update(rt<<1,k,val);
else update(rt<<1|1,k - tree[rt<<1].sum,val);
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
int main()
{
int t,cas = 1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%d %d",&p[i].h,&p[i].k);
sort(p+1,p+1+n);
build(1,1,n);
bool flag = true;
for(int i = 1; i <= n; i++)
{
int tmp = min(p[i].k,n - i - p[i].k); //判断是否是比前面大的有k个,还是后面大的有k个
if(tmp < 0)
{
flag = false;
break;
}
if(p[i].k < n - i - p[i].k)
update(1,p[i].k + 1,p[i].h);
else update(1,n - i - p[i].k + 1,p[i].h);
}
printf("Case #%d: ",cas++);
if(flag == false) printf("impossible\n");
else
{
for(int i = 1; i < n; i++)
printf("%d ",res[i]);
printf("%d\n",res[n]);
}
}
return 0;
}