hdu 5493 Queue(逆序对,线段树)

题目链接: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值