POJ 2828Buy Tickets 解题报告

本文探讨了春节期间中国铁路票务困难的问题,并通过一个实际案例解释了如何利用数学归纳法解决排队问题。详细介绍了如何逆向思考,通过线段树数据结构找到最终排队顺序,提供了解决现实生活中排队问题的有效方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Railway tickets were difficult to buyaround the Lunar New Year in China, so we must get up early and join a longqueue…

The Lunar New Year was approaching, butunluckily the Little Cat still had schedules going here and there. Now, he hadto travel by train to Mianyang, Sichuan Province for the winter camp selectionof 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. Thecold 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 itwas too dark around, such moves would not be discovered even by the peopleadjacent to the queue-jumpers. “If every person in the queue is assigned anintegral value and all the information about those who have jumped the queue andwhere they stand after queue-jumping is given, can I find out the final orderof people in the queue?” Thought the Little Cat.

Input

There will be several test cases in theinput. 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 inthe increasing order of i (1 ≤ i ≤ N).For each i, the ranges and meanings of Posi and Vali areas 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 lineof space-separated integers which are the values of people in the order theystand 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

Hint

The figure below shows how the Little Catfound out the final order of people in the queue described in the first testcase of the sample input.

Source

POJMonthly--2006.05.28, Zhu, Zeyuan

题意:有n个的排队,每一个人都有一个val来对应,每一个后来人都会插入当前队伍的某一个位置pos。要求把队伍最后的状态输出。

逆向思考。数学归纳法证明:在当前队伍为空的情况下,输入中的最后一个人一定会进入他在结果中对应的位置。

假设:在当前队伍为空的情况下,输入中的最后一个人一定会进入他在结果中对应的位置。

第一步:根据题意,输入中的最后一个人(第n个人,Pos_n,Val_n)可以得到结果中对应的位置(第(Pos_n+1)个人)。

第二步:输入中的倒数第二个人(第n-1个人)在最后一个人入队的时候成为待入队的最后一个。根据第一步(假设当前队伍为空,即忽略前面进去的人,条件才符合假设和第一步)可知,他一定可以进入结果中对应的位置。

以此类推,从输入的最后一个到输入的第一个,每个人都可以进入他在结果中对应的位置。

关键在于第二步的:“假设当前队伍为空,即忽略前面进去的人”这句话的实现:每个节点只记录其下的空位置数目。

#include<cstdio>

#include<iostream>

#include<string>

#include<cstring>

#include<cmath>

#include<cstdlib>

#define Mid(a,b)((b+a)>>1)

const int N =200010;

using namespacestd;

intn,pos[N],val[N],ans[N];

 

struct node//节点比较简单,只有区间上下界和该点下面空位置(不包括节点本身)数目

{

    int left; int right; int sum;

    int mid() { return Mid(left, right); }

}tree[N*4];

 

voidbuildtree(int left,int right,int Node)//口诀:先赋值,再判断(是否是叶子),后递归

{

        tree[Node].left = left;  tree[Node].right = right; tree[Node].sum =right - left + 1;//赋值

        if (left !=right)//判断

        {

            int mid = tree[Node].mid();

            buildtree(left,mid,ll(Node));//递归

            buildtree(mid+1,right,rr(Node));//递归

        }

}

int query(intsum_Empty_pos,int Node)

{

        int left = tree[Node].left,right =tree[Node].right;

 

        if (left == right)//叶子

        {

            tree[Node].sum = 0;

            return left;

        }

        else

        {

            int tmpNode;

            if (tree[Node<<1].sum >=sum_Empty_pos) tmpNode = query(sum_Empty_pos, Node<<1);//左儿子下面空位足够多(大于等于需要的),递归左儿子

            else   tmpNode = query(sum_Empty_pos -tree[Node<<1|1].sum , Node<<1|1);//否则右儿子下面的空位置一定满足(大于等于需要的),递归右儿子

            //前面的递归修改数据之后,回溯更新数据

            tree[Node].sum =tree[Node<<1].sum + tree[Node<<1|1].sum;

            return tmpNode;

        }

}

 

int main()

{

   //freopen("output.txt","w",stdout);

  //freopen("input.txt","r",stdin);

    while (scanf("%d",&n)!=EOF)

    {

        buildtree(1,n,1);//数组的第1到第n个元素为原始数据,线段树的根序号为1

 

        for (int i = 1; i <= n; i++)scanf("%d %d",&pos[i],&val[i]);

        for(int i = n; i >=1; i--)

        {

            int ps = query(pos[i]+1,1);//在队伍里前面有pos[i]个人,本人应该是第(pos[i]+1)个人,由于假设位置全为空,其前面有pos[i]个空位即可;

            ans[ps] = val[i];

        }

        for (int i = 1; i < n; i++)printf("%d ",ans[i]);

        printf("%d\n",ans[n]);

    }

    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值