zoukankan      html  css  js  c++  java
  • POJ2828 Buy Tickets(线段树之插队问题)

    飞翔

    问题是这样的:现在有n个人要买票,但是天黑可以随便插队。依次给出将要买票的n个人的数据信息。包含两项:pos,当前第i号人来了之后他肯定要
    插入到pos这个位置,如果当前pos无人,那最好了,直接把他插入即可。但如果pos这个位置有人了,从现实意义上讲,第i号人插入之后,相当于他
    后面的人在原来的基础上都往后挪了一个位置!(ps:这就是为什么人们都讨厌插队的人的原因啊!!!) 每一个人都携带一个val值,当n个人全部确定下
    来之后输出val序列。
     
    分析:可以这样想,就算是你先到的,先排到队的,但是后面来的人可能会排到你的前面,这样你的位置就要往后面挪动,如果我们从前面开始记录的话,这样每次的移动就会TLS,所以,我们可以从后面开始确定位置,因为我后面的位置是已经确定的了,依此往前推!得出答案!!!最后一个问题,在update的时候,怎么决定向左向右深入,上面已经说倒序建树,那么,当在建树的时候,如果左枝剩余的人数少于他的pos(编号),那么就认为左枝的位置放不下他,然后就可以向右枝深入。
     算法结构:采用线段树,每一个节点存储的是当前区间的剩余空位置。
          
    注意一个地方:线段树的下标是从1开始的,而买票的这些人的插队位置是从0开始的,所以理应在查找更新时pos要加1,如果不加1则在判断往哪个子节点
    移动的时候是>pos
    AC代码:
    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    #define lson l , m , rt << 1
    #define rson m + 1 , r , rt << 1 | 1
    
    const int maxn = 200001;
    
    int sum[maxn<<2],pos[maxn],val[maxn],ans[maxn];
    void PushUP(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]=1;
            return ;
        }
        int m = (l+r) >> 1;
        build(lson);
        build(rson);
        PushUP(rt);
    }
    int update(int pos,int l,int r,int rt)
    {
        sum[rt]--;
        if(l==r)
        {
            return l;
        }
    
        int m=(r+l) >> 1 ;
        if(sum[rt<<1]>pos)
            return update(pos,lson);
        else
            return update(pos-sum[rt<<1],rson);
    
    }
    int main( )
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=0 ; i<n ; i++)
            scanf("%d%d",&pos[i],&val[i]);
            build(1,n,1);
            for(int i=n-1 ; i>=0 ; i--)
            {
                ans[update(pos[i],1,n,1)]=val[i];
            }
            for(int i=1 ; i<n ;  i++)
            {
                printf("%d ",ans[i]);
            }
            printf("%d
    ",ans[n]);
        }
        return 0;
    }
    View Code

    小贴士:在往右子的时候 update(pos-sum[rt<<1],rson); 为什么要pos-sum[rt<<1],rson:呢?  可以把结果在子叶点对应的位置看成是最终答案,例如我要排在第3为,而我1,2是左结点的,那我是不是就是要减去左结点的数值,在能是右结点的相对位置

  • 相关阅读:
    synchronized 关键字
    synchronized 关键字
    Linux IPC之共享内存
    链表的插入、删除
    链式队列的实现
    链栈的实现
    双色、三色排序问题
    memmove、memcpy、strcpy、memset的实现
    字符串中去掉多余的空格
    华为机试:从一个数组中选取不同的数(均小于10)组成一个最大的三位数
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9082977.html
Copyright © 2011-2022 走看看