zoukankan      html  css  js  c++  java
  • poj 2828 Buy Tickets 【买票插队找位置 输出最后的位置序列+线段树】

    题目地址:http://poj.org/problem?id=2828

    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 Cat found out the final order of people in the queue described in the first test case of the sample input.

          问题是这样的:现在有n个人要买票,但是天黑可以随便插队。依次给出将要买票的n个人的数据信息。包含两项:pos,当前第i号人来了之后他肯定要
    插入到pos这个位置,如果当前pos无人,那最好了,直接把他插入即可。但如果pos这个位置有人了,从现实意义上讲,第i号人插入之后,相当于他
    后面的人在原来的基础上都往后挪了一个位置!(ps:这就是为什么人们都讨厌插队的人的原因啊!!!) 每一个人都携带一个val值,当n个人全部确定下
    来之后输出val序列。
      分析:很简单的就可以想到,前面的人虽然先到了,但他的位置并不能确定,因为后来的人完全可以插队到你的位置,而你则后移了一个位置。也即是说,
    我们在确定最后的序列时,并不能按照先来后到的顺序处理。我们应该从后往前处理!这样最后到达的人的位置一定是确定的,他的位置绝对是一次就确定的。
    同理往前递推处理。
      算法结构:采用线段树,每一个节点存储的是当前区间的剩余空位置。
         
    注意一个地方:线段树的下标是从1开始的,而买票的这些人的插队位置是从0开始的,所以理应在查找更新时pos要加1,如果不加1则在判断往哪个子节点
    移动的时候是>pos
    code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <math.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    
    struct seq
    {
        int pos, val;
    }a[200000+10];
    
    int num[800000+100];
    int ans[200000+100];
    
    void Build(int rt, int ll, int rr)
    {
        num[rt]=rr-ll+1;
        if(ll==rr)
            return;//已经到达根节点
        Build(rt*2, ll, (ll+rr)/2 );
        Build(rt*2+1, (ll+rr)/2+1, rr );
    }
    
    int update(int pos, int rt, int ll, int rr)
    {
        num[rt]--;//空位置数量-1
        if(ll==rr)
            return ll;//到达根节点
        if(num[rt*2]>pos)//pos是从0开始的 而线段树是从1开始存储的 但0和1在此题中是对应存储的
            return update(pos, rt*2, ll, (ll+rr)/2);
        else
            return update(pos-num[rt*2], rt*2+1, (ll+rr)/2+1, rr);
    }
    
    int main()
    {
        int n, i;
        while(scanf("%d", &n)!=EOF)
        {
            for(i=0; i<n; i++){
                scanf("%d %d", &a[i].pos, &a[i].val);
            }//打表保存
            Build(1, 1, n);//从1号节点开始建树 区间[1,n]
    
      /*      for(i=1; i<=7; i++)
                printf("%d---", num[i]); */
    
            for(i=n-1; i>=0; i--){
                ans[update(a[i].pos, 1, 1, n)]=a[i].val;
                //
            }
            for(i=1; i<=n; i++){
                printf("%d%c", ans[i], i==n?'
    ':' ');
            }
        }
        return 0;
    }
    
  • 相关阅读:
    HDU4812 D Tree(树的点分治)
    BZOJ1834 [ZJOI2010]network 网络扩容(最小费用最大流)
    HDU4862 Jump(放大边权的费用流)
    SCU3185 Black and white(二分图最大点权独立集)
    HDU3729 I'm Telling the Truth(字典序最大的最大流)
    HDU3586 Information Disturbing(树形DP)
    HDU3657 Game(最小割)
    POJ3162 Walking Race(树形DP+尺取法+单调队列)
    SCU3312 Stockholm Knights(最大流)
    Codeforces 161D Distance in Tree(树的点分治)
  • 原文地址:https://www.cnblogs.com/yspworld/p/4741503.html
Copyright © 2011-2022 走看看