poj 2828 Buy Tickets(线段树点区)

题目链接:   http://poj.org/problem?id=2828

题目大意:   有N个人在排队买票,每个人可站的位置从0到N

                  后面来的人可能会插队,也有可能站在当前队伍的最后面

                  N行,每行两个数,pas表示刚来的这个人会站在当前队伍的第pas位置上

                  val表示这个人对应的值(0<=val<=i-1),最后按每个人所在的位置输出其相应的值

解题思路:   后面加入的人,必定会站在当前队伍之间或者最后面

                  因为后面加入的人一定会改变前面确定的顺序,所以从后往前来确定队伍的顺序,先看一组数据

                   0  2

                   1  1

                   1  38

                   0  31

                   初始化序列为 -1 -1 -1 -1 (-1表示这个位置没有被确定)

                   0 31,把值为31的人插入到剩余未确定位置中的第0个位置,得到序列 31 -1 -1 -1

                   1 38,把值为38的人插入到剩余未确定位置中的第1个位置,得到序列 31 -1 38 -1

                   以此类推最后的序列为 31 2 38 1

                   为什么每次加入的位置剩余空位的第val个呢?

                   因为我们是从后面往前的,后面加入的数不会影响比它之前的数所在的位置。

                   用线段树O(logN)找出左到右的第pas个位置(找出之后再往上更新),最下层的结点初始化值为1,其余的结点存储区间值的总和

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INF 0x3f3f3f3f
#define MAX 200100
#define MID(a,b) (a+b)>>1
#define L(a) a<<1
#define R(a) (a<<1|1)
typedef struct{
      int left,right,num;
}Node;
Node Tree[MAX<<2];
int pas[MAX],val[MAX],ans[MAX],kk,n;

void Build(int t,int l,int r)
{
     Tree[t].left=l,Tree[t].right=r;
     if(Tree[t].left==Tree[t].right)
     {
           Tree[t].num=1;        //初始化为1
           return ;
     }
     int mid=MID(Tree[t].left,Tree[t].right); 
     Build(L(t),l,mid);
     Build(R(t),mid+1,r);
     Tree[t].num=Tree[L(t)].num+Tree[R(t)].num;
} 

void Query(int t,int l,int r,int m)
{
     if(Tree[t].left==Tree[t].right)
     {
         kk=Tree[t].left;       //找到结点,并且标记
         Tree[t].num--;
         return ;
     }            
     int mid=MID(Tree[t].left,Tree[t].right);
     if(Tree[L(t)].num>=m)       //满足条件时优先选择左子树
     {
         Query(L(t),l,mid,m);
     }
     else                        //否则选择右子树
     {
         Query(R(t),mid+1,r,m-Tree[L(t)].num);
     }
     Tree[t].num=Tree[L(t)].num+Tree[R(t)].num;    //更新
}

int main()
{
    int i,j,k,m,temp;
    while(scanf("%d",&n)!=EOF)
    {
         memset(Tree,0,sizeof(Tree));
         Build(1,1,n);
         for(i=1;i<=n;i++)
              scanf("%d%d",&pas[i],&val[i]);
         for(i=n;i>=1;i--)
         {
              Query(1,1,n,pas[i]+1);          //查找剩余空位中的第pas[i]个位置所在的点
              ans[kk]=val[i];                 //标记点
         }
         for(i=1;i<=n;i++)
              printf("%d%c",ans[i],i==n?'\n':' ');
    }
    return 0;
}


注:原创文章,转载请注明出处

 

                  

你可能感兴趣的:(线段树,poj)