zoukankan      html  css  js  c++  java
  • POJ 2828 Buy Tickets(线段树)

    点我看题目 

    题意 :说实话,看题的时候根本没怎么看懂,每个单词我倒是认识,但是拼一块儿我觉得就有点拗口了,一开始我以为的站右边是以为队伍如果画出来应该是上下的,谁知看了底下的那个样例解释才知道原来队伍时左右的,,,难怪说插到右边呢。。。。大概题意就是,队列中的每个人都被赋一个特定的值,给出所有插队的人及他们插队后他们所站的位置信息,然后输出队列中的人的最终的排列顺序。

    思路 :首先处理数据,不要从前往后处理,从后往前处理,因为后边的人是会影响前边的人的位置的。用线段树的每个结点记录这个区间中的空位置数,每次插入的时候将这个人放在第pos[i]个空格的地方,因为后边的人如果排在前面人的前面,那么我们对前面的人进行操作的时候,那个位置就会被占了,前面人的位置就会向后移一格。这样就可以用线段树来处理了。

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    const int maxn = 200100 ;
    
    using namespace std;
    
    int pos[maxn],val[maxn],size[maxn*3],ans[maxn],point[maxn] ;
    //第i个人的属性值为val[i],插入第pos[i]+1个空格位置
    //ans[i]是指排列中第i个位置的队员序号,在线段树中区间[k]的叶节点序号为point[k]
    //线段树中结点j所代表区间的空位数为size[j]
    int n ;
    
    void build(int l,int r,int x)//从结点x出发,构造区间(l,r)的线段树
    {
        size[x] = r-l+1 ;           // 存储结点x所代表区间空位置数
        if(l == r)//若该区间仅一个元素,则设置该元素的叶节点序号
        {
            point[l] = x ;
            return ;
        }
        int mid = (l+r)/2 ;
        build(l,mid,x+x) ;
        build(mid+1,r,x+x+1) ;
    }
    
    int countt(int sum,int l,int r,int x)//计算第sum个空位的叶节点序号
    {
        if(l == r)
        return l ;
        int mid = (l+r)/2 ;
        if(size[x+x] >= sum)//若左子树的空位数不少于sum则递归左子树
        return countt(sum,l,mid,x+x) ;
        return countt(sum-size[x+x],mid+1,r,x+x+1) ;
    }
    
    void get(int i)//从叶节点序号i出发向上调整所在字树的空位数
    {
        while(i > 0)
        {
            size[i]-- ;
            i = i/2 ;
        }
    }
    
    void Init()
    {
        for(int i = 1 ; i <= n ; i++)
        scanf("%d %d",&pos[i],&val[i]) ;
    }
    
    void solve()
    {
        memset(size,0,sizeof(size)) ;
        build(1,n,1) ;
        for(int i = n ; i >= 1 ; i--)
        {
            int temp = countt(pos[i]+1,1,n,1) ;
            ans[temp] = i ;
            get(point[temp]) ;
        }
        for(int i = 1 ; i <= n-1 ; i++)
        printf("%d ",val[ans[i]]) ;
        printf("%d
    ",val[ans[n]]) ;
    }
    int main()
    {
        while(~scanf("%d
    ",&n))
        {
            Init() ;
            solve() ;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    土豆案例(display:none和block的应用)
    显示和隐藏
    鼠标经过提高层级案例(margin,相对定位,z-index)
    垂直对齐vertical-align
    表单初始化
    使用定位隐式转换为行内块元素
    清除浮动的方法
    定位的盒子叠放顺序z-index
    FreeRTOS-为什么关中断之后切换进程?
    PowerPC-关闭中断后,还能报sc中断?
  • 原文地址:https://www.cnblogs.com/luyingfeng/p/3557159.html
Copyright © 2011-2022 走看看