poj 2828

Buy Tickets

Description

Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue…

The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he had to travel by train to Mianyang, Sichuan Province for the winter camp selection of the national team of Olympiad in Informatics.

It was one o’clock a.m. and dark outside. Chill wind from the northwest did not scare off the people in the queue. The cold night gave the Little Cat a shiver. Why not find a problem to think about? That was none the less better than freezing to death!

People kept jumping the queue. Since it was too dark around, such moves would not be discovered even by the people adjacent to the queue-jumpers. “If every person in the queue is assigned an integral value and all the information about those who have jumped the queue and where they stand after queue-jumping is given, can I find out the final order of people in the queue?” Thought the Little Cat.

Input

There will be several test cases in the input. Each test case consists of N + 1 lines where N (1 ≤ N ≤ 200,000) is given in the first line of the test case. The next N lines contain the pairs of values Posi and Vali in the increasing order of i (1 ≤ i ≤ N). For each i, the ranges and meanings of Posi and Valiare as follows:

  • Posi ∈ [0, i − 1] — The i-th person came to the queue and stood right behind the Posi-th person in the queue. The booking office was considered the 0th person and the person at the front of the queue was considered the first person in the queue.
  • Vali ∈ [0, 32767] — The i-th person was assigned the value Vali.

There no blank lines between test cases. Proceed to the end of input.

Output

For each test cases, output a single line of space-separated integers which are the values of people in the order they stand in the queue.

Sample Input

4
0 77
1 51
1 33
2 69
4
0 20523
1 19243
1 3890
0 31492

Sample Output

77 33 69 51
31492 20523 3890 19243
 
题目大意:插队问题。已知有N个人,一开始队列为空,编号从1到N,可以看作所有人
                  都排在0号的后面(0号不存在)。分别读入N个人的pos 和 val,pos 表示插
                  队在 pos号人的后面(如pos = 0, 即插入到第1位),val 可以看作是读入的
                  人的一个标识。求经过N次插队以后(插队一定成功),最终的队列(输出这
                  个队列每个人的标识值)。

思      路: 刚开始知道用线段树没有思路,看了别人的总结慢慢的学会往正确的方向上想了。
                 
                 这道题就是倒着从最后一个开始找,找到那个之前有data[i]个空位的序号、详情见代码解释。

                 线段树相当于统计一些离散化的数或者点,建树的过程中已经把他们的序号存储下了,
                 把他们都个体化之后对于共同的特点进行统计。
                 见过几道题情况大致为:
                  1 : 在某些范围内修改或者变动数据。此时序号和数据无关,sum数组存储数据的和
                         同时需要不断的更新sum数组。
                  2 :查找一系列数的逆序数。查找已经出现的比每个数大的数的个数,sum存储的是
                        结点的个数之和,在题目要求的情况下序号正好是数据,因此通过查找sum值并且
                        更新就可以找到答案。
                 3 : 第三类就是这种情况了,将每个数据看成个体,查找第n个数的后一位的序号。
                        sum存储的是未被使用的结点的个数

                 值得注意的是,在query返回值得时候,要考虑是当前这个还是下一个。
                  if (i < n )   返回的是符合i<n的下一个
                  if (i< = n)  返回的是符合i<=n的当前这个
                   还要注意sum数组代表的含义。要理清序号,sum数组值,当前查找的i (j)之间的关系

代码如下:
<pre name="code" class="cpp">/*踏实!!努力!!*/
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<map>
#include<queue>
#include<stack>
using namespace std;
#define N 200010
int n;
int sum[N<<2];
struct{
    int pos;
    int val;
}data[N];
void build(int l,int r,int cur)
{
    if(l==r){
        sum[cur]=1;
        //初始的时候每个位置都标记一下
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,cur<<1);
    build(mid+1,r,cur<<1|1);
    sum[cur]=sum[cur<<1]+sum[cur<<1|1];
    return ;
}
int query(int i,int l,int r,int cur)
{
    if(l==r){
        sum[cur]=0;
        return l;
    }
    int ans=0;
    int mid=(l+r)>>1;
    //注意这里不是i<=sum[cur<<1]查找的是前面有i个空位的位置
    if(i<sum[cur<<1])
        ans=query(i,l,mid,cur<<1);
    //注意这里是i-sum[cur<<1]  查找的数量发生变化
    else
        ans=query(i-sum[cur<<1],mid+1,r,cur<<1|1);
    sum[cur]=sum[cur<<1]+sum[cur<<1|1];
    return ans;
}
int main()
{
    int ans[N];
    while(scanf("%d",&n)!=EOF){
        build(1,n,1);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&data[i].pos,&data[i].val);
        for(int i=n;i>=1;i--){
            int index=query(data[i].pos,1,n,1);
            ans[index]=data[i].val;//存储对应位置的val值
        }
        printf("%d",ans[1]);
        for(int i=2;i<=n;i++)
            printf(" %d",ans[i]);
        printf("\n");
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值