【ybtoj高效进阶 21265】排队问题(fhq-Treap)(构造)

排队问题

题目链接:ybtoj高效进阶 21265

题目大意

给你每个人的身高和要求,每个人的身高都不同。
每个人的要求是要它左边比他高的人或右边比他高的人个数是它给出的值。
然后要你找出字典序最小的满足的身高序列。

思路

我们考虑把人按身高从小到大排序,然后我们不难想到如果把身高一样的排在一起,然后我们一起填,那这个时候,我们其实就是要它填入的位置左边或右边是它给出的值即可。

首先判不可能的条件,即比它大的个数小于它的值。
那接着我们会有两个可以放的位置,那由于要字典序最小,我们是从小到大放的,所以我们就调哪个靠左放哪个即可。
那放我们考虑有点类似链表的插入,这里用的是 fhq-Treap。

然后由于你要消除相同身高的影响,我们考虑先放位置后的,再放位置前的。
所以你排个序就好了。

代码

#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; struct node { int a, b; }a[100001]; int n; bool cmp(node x, node y) { if (x.a != y.a) return x.a > y.a; return x.b > y.b; } struct fhq_treap {//平衡树 int rd[100001], ls[100001], rs[100001]; int a[100001], sz[100001], tot, root; int make_new(int val) { int now = ++tot; a[now] = val; sz[now] = 1; ls[now] = rs[now] = 0; rd[now] = rand(); return now; } void up(int now) { sz[now] = sz[ls[now]] + sz[rs[now]] + 1; } int merge(int x, int y) { if (!x || !y) return x + y; if (rd[x] > rd[y]) { rs[x] = merge(rs[x], y); up(x); return x; } else { ls[y] = merge(x, ls[y]); up(y); return y; } } pair <int, int> split_rnk(int now, int rnk) { if (!now) return make_pair(0, 0); if (!rnk) return make_pair(0, now); pair <int, int> re; if (rnk <= sz[ls[now]]) { re = split_rnk(ls[now], rnk); ls[now] = re.second; up(now); re.second = now; } else { re = split_rnk(rs[now], rnk - sz[ls[now]] - 1); rs[now] = re.first; up(now); re.first = now; } return re; } int insert(int val, int rnk) { int now = make_new(val); pair <int, int> re = split_rnk(root, rnk); return merge(merge(re.first, now), re.second); } void write(int now) { if (!now) return ; write(ls[now]); printf("%d ", a[now]); write(rs[now]); } }T; int main() { // freopen("queue.in", "r", stdin); // freopen("queue.out", "w", stdout); srand(1919810); scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d %d", &a[i].a, &a[i].b); sort(a + 1, a + n + 1, cmp); for (int i = 1; i <= n; i++) { int ii = i; if (a[ii].b > i - 1) {//比它高的人没有那么多 printf("impossible"); return 0; } if ((i - 1) - a[ii].b < a[ii].b) a[ii].b = (i - 1) - a[ii].b;//反过来更前面 while (ii < n && a[ii + 1].a == a[ii].a) {//把相同的都找出来 ii++; if (a[ii].b > i - 1) {//跟前面一个道理 printf("impossible"); return 0; } if ((i - 1) - a[ii].b < a[ii].b) a[ii].b = (i - 1) - a[ii].b; } sort(a + i, a + ii + 1, cmp);//重新排一次序,排出 b(因为你前面可能会改 b) for (int j = i; j <= ii; j++) {//一个一个放 T.root = T.insert(a[j].a, a[j].b); } i = ii; } T.write(T.root); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBTOJ_GXJJ_21265.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(24)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示