题目链接:点击查看

题目大意:给出n个人,一个队列,一开始队列是空的,每个人加入的时候都会插入到指定位置pos的后面,即插队,问最后队列的排列情况是怎么样的

题目分析:一开始很难想到是线段树的题目,毕竟这题目正儿八经的方法还能用树状数组,数据范围小点还可以贪心或暴力都可以解决,可是这个题的n是2e5,如果暴力n*n肯定就爆掉了,只能优化成logn才行。

不多废话了,这个题目其实就是经典题目:求1~n中第K大的树 这个题目的一种变形,求1~n中第K大的话看到第K大的第一反应肯定是主席树,因为前几天刚学了这么高大上的高级数据结构,所以有点蠢蠢欲动的想敲板子试一试,话说回来,主席树解决的是随机区间[l,r]内的第K大的数,而这个题目的区间是给定了,[1,n],所以不用给自己找麻烦,我们只需要建立一个线段树,线段树的范围是1~n,维护的是区间内有多少个点还没被用过,用sum来表示,那么我们如果想找第K大的数,可以用query函数二分去查找相应的点,如果找到了就返回位置(位置就是这个数字本身),找不到可以返回-1(当然这个题的数据保证了都能找到相应的位置),记得每次询问的时候都要将这条链上的sum减一,因为我们要找的这个点马上就要用掉了,我们的sum维护的是还没有用过的点,这样每次询问都会修改logn个点,时间复杂度也就变为logn级别的了。

上面是讲了如何求1~n中第k大的数,那么和这个题目又有什么关系呢?这个题的题意我稍微转换一下,每个人插入的时候不都是插入到pos后面的那个位置嘛,那么不就是,当这个人插入到队列中时,是第(pos+1)大的,而后面插进队伍的人只会影响到前面的人,因为前面已经排好的序列被插队的人打乱了嘛,所以我们从最后一个人开始倒着遍历,因为最后一个人插入队伍之后,就没有人影响他的序列了,所以这个人就是n个人队伍中的第(pos+1)大的人,在1~n中找到第(pos+1)大的数就是第n个人的序号了,这个时候将第n个人删除掉,因为已经处理完了嘛,删除掉第n个人后,第n-1个人便成了最后一个人,再找到第n-1个人的第(pos+1)的位置就是第n-1个人的序号了,这样以此类推从后往前遍历,就能以nlogn的时间复杂度完成任务啦

2020.3.8更新:

这个题目在练习Splay时再次碰到,发现可以直接用Splay模拟,只不过常数比较大,不过问题不大

每次插队时,如果队列为空记得特判一下,如果pos[ i ] == 0 时也要特判一下 ,此时新插入的人在最前面,也就是可以直接作为根节点,其余情况我们找出第 pos[ i ] 的结点,将其旋转到根节点,然后变为当前插入节点的左子树就好了,最后dfs中序遍历就是答案了,这个题需要对insert按照理解重写,还是有一点小难度的

上代码吧:

线段树:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e5+100;struct node
{int pos,val;
}a[N];struct Node
{int l,r,sum;//sum记录的是还没有被标记过的人有多少个
}tree[N<<2];void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].sum=r-l+1;//初始化时sum初始化为区间长度if(l==r)return;int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}int query(int k,int num)
{tree[k].sum--;//查询的同时别忘了减一if(tree[k].l==tree[k].r)return tree[k].l;if(tree[k<<1].sum>=num)//如果当前的数字比左区间内的总数字数目要小,那么该数字必定在左区间return query(k<<1,num);else//否则就去右区间内查找return query(k<<1|1,num-tree[k<<1].sum/*记得这里如果去了右区间,那么要查找的第K大的数就变为了第(K-左儿子数目)大了,想一想,是不是?*/);
}int ans[N];int main()
{
//  freopen("input.txt","r",stdin);int n;while(scanf("%d",&n)!=EOF){for(int i=1;i<=n;i++){scanf("%d%d",&a[i].pos,&a[i].val);a[i].pos++;//每个pos都加一,来表示属于第K大}build(1,1,n);for(int i=n;i>=1;i--){int pos=query(1,a[i].pos);ans[pos]=a[i].val;}printf("%d",ans[1]);for(int i=2;i<=n;i++)printf(" %d",ans[i]);cout<<endl;}return 0;
}

Splay:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=2e5+100;class Splay
{public:int ch[N][2],f[N],size[N],key[N];//size:子树大小,cnt:当前节点出现次数,key:权值 int val[N];int sz,root;inline void clear(int x){ch[x][0]=ch[x][1]=f[x]=size[x]=key[x]=0;}inline bool get(int x){return ch[f[x]][1]==x;}inline void update(int x){if(x){size[x]=1;if(ch[x][0]) size[x]+=size[ch[x][0]];if(ch[x][1]) size[x]+=size[ch[x][1]];}}inline void rotate(int x){int old=f[x],oldf=f[old],whichx=get(x);ch[old][whichx]=ch[x][whichx^1]; f[ch[old][whichx]]=old;ch[x][whichx^1]=old; f[old]=x;f[x]=oldf;if(oldf)ch[oldf][ch[oldf][1]==old]=x;update(old); update(x);}inline void splay(int x){for(int fa;fa=f[x];rotate(x))if(f[fa])rotate((get(x)==get(fa))?fa:x);root=x;}inline void insert(int x,int v){clear(sz+1);if(root==0)//空树 {sz++; ch[sz][0]=ch[sz][1]=f[sz]=0; root=sz; size[sz]=1; key[sz]=x; val[sz]=v;return;}if(x==0){int now=root;while(ch[now][0])now=ch[now][0];sz++;ch[sz][0]=ch[sz][1]=0;f[sz]=now;size[sz]=1;val[sz]=v;update(now);splay(sz);return;}int now=findx(x);splay(now);sz++;ch[sz][0]=now;f[now]=sz;ch[sz][1]=ch[now][1];f[ch[now][1]]=sz;ch[now][1]=0;val[sz]=v;root=sz;update(now);update(sz);return;}inline int findx(int x)//找到排名为x的点{int now=root;while(1){if(ch[now][0]&&x<=size[ch[now][0]])now=ch[now][0];else{int temp=(ch[now][0]?size[ch[now][0]]:0)+1;if(x<=temp) return now;x-=temp; now=ch[now][1];}}}inline int pre()//小于某个数的最大值 {int now=ch[root][0];while(ch[now][1]) now=ch[now][1];return now;}inline int next()//大于某个数的最小值 {int now=ch[root][1];while(ch[now][0]) now=ch[now][0];return now;}void dfs(int now){if(!now)return;dfs(ch[now][0]);printf("%d ",val[now]);dfs(ch[now][1]);}
}tree;int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int n;while(scanf("%d",&n)!=EOF){tree.sz=tree.root=0;for(int i=1;i<=n;i++){int pos,val;scanf("%d%d",&pos,&val);tree.insert(pos,val);}tree.dfs(tree.root);putchar('\n');}return 0;
}

POJ - 2828 Buy Tickets(线段树+思维/Splay+模拟)相关推荐

  1. POJ 2828 Buy Tickets 线段树

    题目: http://poj.org/problem?id=2828 很巧妙的题,逆序插入线段树,这样元素不用移动.用二叉排序树也能过. 1 #include <stdio.h> 2 #i ...

  2. POJ 2828 Buy Tickets | 线段树的喵用

    题意: 给你n次插队操作,每次两个数,pos,w,意为在pos后插入一个权值为w的数; 最后输出1~n的权值 题解: 首先可以发现,最后一次插入的位置是准确的位置 所以这个就变成了若干个子问题, 所以 ...

  3. poj 2828 Buy Tickets

    http://poj.org/problem?id=2828 题意:在一个队列里,有人依次向第pos个位置插入,求最后的序列: 思路:用线段树存储区间内剩余的没有被占的位置,注意插入的时候要从后向前插 ...

  4. #树状数组#poj 2828 Buy Tickets

    题目 输入插队的人和插队的位置,求最终所有人的位置. 分析 树状数组,从后往前(倒推),然后就是要让在前面的次序-1. 代码 #include <cstdio> #include < ...

  5. POJ 2828. Buy Tickets

    链接 http://poj.org/problem?id=2828 题意 有 NNN 个人排队,每一个人都有一个权值 valvalval ,每一个人都会按顺序插入到当前队伍的某一个位置 posposp ...

  6. 二逼平衡树——树套树(线段树套Splay平衡树)

    题面 Bzoj3196 解析 线段树和Splay两棵树套在一起,常数直逼inf,但最终侥幸过了 思路还是比较简单, 在原数组维护一个下标线段树,再在每一个线段树节点,维护一个对应区间的权值Splay. ...

  7. 牛客小白月赛28 E-会当凌绝顶,一览众山小 线段树+二分暴力模拟

    牛客小白月赛28 E-会当凌绝顶,一览众山小 线段树+二分暴力模拟 题意 思路 Code 传送门: https://ac.nowcoder.com/acm/contest/16081/E 题意 登山顺 ...

  8. 【POJ】2828 Buy Tickets(线段树+特殊的技巧/splay)

    http://poj.org/problem?id=2828 一开始敲了个splay,直接模拟. tle了.. 常数太大.. 好吧,说是用线段树.. 而且思想很拽.. (貌似很久以前写过貌似的,,) ...

  9. POJ 3667 Hotel(线段树)

    POJ 3667 Hotel 题目链接 题意:有n个房间,如今有两个操作 1.找到连续长度a的空房间.入住,要尽量靠左边,假设有输出最左边的房间标号,假设没有输出0 2.清空[a, a + b - 1 ...

最新文章

  1. 我的小前端 (4)—— 多余字数用省略号显示
  2. delphi base64 java_Base64以及delphi、Java实现[转]
  3. php 输入值,php-HTML输入值更改
  4. 作为一名前端开发工程师,你必须掌握的WEB模板引擎:Handlebars
  5. 水平+垂直布局-css (借鉴)
  6. python 元类 详解_Python 元类详解 __new__、__init__、__call__、__metacalss__
  7. java.util.ResourceBundle用法
  8. MongoDB的ObjectId生成原理
  9. 46、练习:输出指定目录下的所有文件名称
  10. PKD-Bert:基于多层网络的Bert知识蒸馏
  11. DM8168外挂IC卡读写异常
  12. 设计师谈中望CAD2010应用心得 作者:刘国勤
  13. 非常好用的节假日查询接口
  14. “2021云管和云网大会”在京召开
  15. 读书笔记—情商:为什么情商比智商更重要
  16. RxJava 学习笔记(七) --- Filtering 过滤操作
  17. flutter整合极光推送完美版
  18. Windows10企业英文版下载 2022-2-17更新
  19. 基于Redis的BloomFilter实现
  20. 王小云数学与计算机奖,2019未来科学大奖揭晓, 清华大学、山东大学教授王小云获“数学与计算机科学”奖...

热门文章

  1. 集中式整合之加入springsecurity
  2. G1与CMS的区别是什么
  3. 数据库-优化-pt-query-digest使用简介
  4. Redisson分布式锁实战-2:解决wait_time之坑
  5. 整合Tomcat和Nginx实现动静态负载均衡
  6. jQuery版本的网页开关灯、jQuery版本网页开关灯的另一种写法
  7. c语言中 c2059错误是,解决error C2059: 语法错误:“::”问题
  8. 加载torchvision中预训练好的模型并修改默认下载路径
  9. supervisor配置文件中如何添加多个环境变量
  10. 【文文殿下】网络流学习笔记