poj~2828(线段树)

Buy Tickets

做到现在,发现线段数有一个很关键的问题,建树的数组得开的比题目数据大很多,最好开3倍的题目数据范围。


题意:有n个人买票,除了第一个人,后面的n-1个人都会插队,插队的位置为pos[i],每个人有一个值val[i]。

从1~n按顺序输出排完队后的所有人val值。


1.对于前x个人来说,第x+1个人的位置肯定是固定的,所以从后面往前遍历。

2.结构体中pos记录当前区间剩余空间数。

3.若该节点的左儿子空间不够,则遍历右儿子,且所占空间-左儿子的剩余空间//这个规律是看别人的博客知道的,智商不够,理解不了哇T^T。

4.大牛图解


具体还是看代码吧,详细注释:


#include <stdio.h>
#define MAX 600005      //数组开三倍

struct ac
{
    int l,r;
    int pos;        //记录当前区间的剩余空间
}seat[MAX+5];

int n,pos[MAX+5],val[MAX+5];    //存插入位置和val值
int num[MAX+5];         //存输出的值

void build(int l,int r,int k)  //标准建树
{
    seat[k].l=l;
    seat[k].r=r;
    seat[k].pos=r-l+1;      //剩余空间初始化
    if(l==r)
        return ;
    int mid=(l+r)/2;
    build(l,mid,2*k);
    build(mid+1,r,2*k+1);
}

void insert(int pos,int val,int k)
{
    seat[k].pos--;                  //当前位置的剩余空间-1
   // printf("k:%d pos:%d\n",k,seat[k].pos);
    if(seat[k].l==seat[k].r)
    {
        num[seat[k].l]=val;
        seat[k].pos=0; //叶子存了数,剩余空间就为0了,这里改成seat[k].pos--也是一样的
        return ;
    }
    if(pos<=seat[2*k].pos)      //若左节点剩余空间足够容纳pos
        insert(pos,val,2*k);
    else
        insert(pos-seat[2*k].pos,val,2*k+1);    //否则pos-左节点剩余空间,遍历右节点
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        build(1,n,1);   //标准建树
        int i;
        for(i=1;i<=n;i++)
        {
            scanf("%d %d",&pos[i],&val[i]);
            pos[i]++;                   //因为该题是从0~n-1,转化成1~n
        }
        for(i=n;i>=1;i--)       //倒叙插入
            insert(pos[i],val[i],1);
        for(i=1;i<=n;i++)
        {
            printf("%d",num[i]);
            if(i==n)
                printf("\n");
            else
                printf(" ");
        }
    }
    return 0;
}

一开始知道这个是线段树的题,但看到这个题目一点思路都没有,也不知道线段树存什么。

感觉距离完全掌握线段树还有很长的路要走。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值