POJ_2828_Buy Tickets

题意:插队问题;

 2016.5.20,复习这道题。

 

总结:线段树基础不牢,建树,更新尚不熟悉,注意加强理解记忆。

 

主要理解:(单点更新,逆序插入)

发生插队时,前面的队伍是连续没有空位的,即pos:2,1,这种情况不会出现,至少应该为pos:1,2,1

插入顺序是逆序的(最后插入的val的位置不会再发生变化),如果正序插入则每个val的顺序是动态的。

插入pos,那么在pos这个位置之前应该还有pos-1个空位。

访问右节点的时候注意pos要修改,改为pos-sum[rt],即整个线段的第pos个空位,在下一个右儿子那的第pos-sum[rt]个空位。

void Insert(int pos,int val,int l,int r,int rt)
{
    if(l==r)
    {
        spare[rt]=0;
        seq[l]=val;
        return;
    }
    int mid=(r+l)>>1;
    if(pos<=spare[rt<<1])
        Insert(pos,val,l,mid,rt<<1);
    else
        Insert(pos-spare[rt<<1],val,mid+1,r,rt<<1|1);
    PushUp(rt);
}

 

 

 

代码:

#include<iostream>
#include<cstdio>
using namespace std;

#define N 200005

int spare[N<<2];
int seq[N];

void PushUp(int rt)
{
    spare[rt]=spare[rt<<1]+spare[rt<<1|1];
}

void build(int l,int r,int rt)
{
    if(l==r)
    {
        spare[rt]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    PushUp(rt);
}

void Insert(int pos,int val,int l,int r,int rt)
{
    if(l==r)
    {
        spare[rt]=0;
        seq[l]=val;
        return;
    }
    int mid=(r+l)>>1;
    if(pos<=spare[rt<<1])
        Insert(pos,val,l,mid,rt<<1);
    else
        Insert(pos-spare[rt<<1],val,mid+1,r,rt<<1|1);
    PushUp(rt);
}

int main()
{
    int n,p[N],v[N];
    while(scanf("%d",&n)!=EOF)
    {
        build(1,n,1);
        int i;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&p[i],&v[i]);
            p[i]++;
        }
        for(i=n;i>0;i--)
        {
            Insert(p[i],v[i],1,n,1);
        }
        for(i=1;i<=n;i++)
        {
            if(i!=n)
                printf("%d ",seq[i]);
            else
                printf("%d\n",seq[i]);
        }
     /*for(i=1;i<=n;i++)         //如果这样输出就会超时,线段树容易超时
        {
       printf("%d",seq[i]); if(i!=n) printf(" "); else printf("\n"); }*/
} return 0; }

  

posted on 2015-08-15 11:33  JASONlee3  阅读(250)  评论(0编辑  收藏  举报

导航