poj 2288 Buy Tickets

这道题是从最后一个数开始建立线段树,区间存储的范围是该区间有多少个空位剩余,对于最后一个插入的数,它肯定和其插入的位置一致,例如对于测试数据的第一组,69插入2这个位置,是肯定的,它将前面占有2位置的数向后面推,同理对于倒数第二个数,占有1这个位置,如果前面有数占有1这个位置,此时前面的必定是向后面推。假设P为插入的位置,因次每次查看左区间有没有大于等于p的空位,如果有则搜索,否者搜索右孩子。

#include<cstdio>

#include<cstdlib>

#include<cmath>

#include<cstring>

#define MAXN 200005

int seg_tree[MAXN<<2];

void build_tree(int l,int r,int id);

void push_up_tree(int id);

void update_tree(int left,int right,int l,int r,int id);

int ans[MAXN],cur;

struct Node

{

    int i;

    int num;

};

Node temp[MAXN];

int main()

{

        int n,i,j,k;

    while(scanf("%d",&n)==1)

    {

        build_tree(1,n,1);

        for(i=1;i<=n;i++)

        {scanf("%d%d",&temp[i].i,&temp[i].num);}

        for(i=n;i>0;i--)

           {

               cur=temp[i].num;

               update_tree(temp[i].i+1,n,1,n,1);



                   }

        for(i=1;i<=n;i++)

        {if(i-1) printf(" ");

            printf("%d",ans[i]);

        }

        printf("\n");



    }



   

}

void build_tree(int l,int r,int id)

{

        if(l==r)

    {

        seg_tree[id]=1;

        return ;

    }

  int m=(l+r)>>1;

  build_tree(l,m,id<<1);

  build_tree(m+1,r,id<<1|1);

  push_up_tree(id);

    

}

void push_up_tree(int id)

{

    seg_tree[id]=seg_tree[id<<1]+seg_tree[id<<1|1];

}

void update_tree(int left,int right,int l,int r,int id)

{

    if(l==r)

    {

        seg_tree[id]--;

        ans[l]=cur;



        return ;

    }

    int m=(l+r)>>1;

        if(left<=seg_tree[id<<1])

        update_tree(left,right,l,m,id<<1);

    else 

    {

        left-=seg_tree[id<<1];

        update_tree(left,right,m+1,r,id<<1|1);

    }

    push_up_tree(id);

}

 

 

你可能感兴趣的:(poj)