POJ2828 Buy Tickets 线段树好题

POJ2828 Buy Tickets

题意:插队问题;

关键:如何插入这几个节点,每个节点储存什么信息。

类型:很基本的单点更新线段树

思路:这题想到了就水了,数据逆着插入,最先插入的一个数据的位置明显是题目给定的位置,可以确定,然后插入的几个数根据的位置前面插入的数据来决定,

用sum[]数组表示改线段空位置的个数,满足 pos<=sum[rt<<1](即左儿子的空位多于插入数的位置序号)就访问左儿子,否则访问右儿子

(访问右节点的时候注意pos要修改,改为pos-sum[rt],即整个线段的第pos个空位,在下一个右儿子那的第pos-sum[rt]个空位)。
对自己的总结: 刚学线段树,诶,这题刷了一下午,看来线段树的基础还不够,要加油了;

下面是我的AC代码。

View Code
#include<stdio.h>
#include<string.h>

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define mid int m = (l + r)>>1
#define maxn 200000

int sum[maxn<<2],pos[maxn],val[maxn],ans[maxn<<2];//ans储存插入的值;

void push_up(int rt)
{
    sum [rt] = sum[rt<<1]+sum[rt<<1|1];
}
void build(int l, int r, int rt)
{
    sum[rt]=r-l+1;
    if(l == r)return;
    mid;
    build(lson);
    build(rson);
}
void update(int pos, int val, int l, int r, int rt)
{
    if(l == r){ans[rt]=val;sum[rt]--;return;}
    mid;
    if(pos <= sum[rt<<1])update(pos, val, lson); //根据左右儿子空位的多少和插入数据的位置比较来确定插入哪个儿子
    else update(pos -sum[rt<<1], val, rson);
    push_up(rt);
}
void print(int l, int r, int rt)
{
    if(l == r){printf("%d ",ans[rt]);return;}
    mid;
    print(lson);
    print(rson);
}
int main()
{
    int n,i;
    while(~scanf("%d",&n))
    {
        for(i=0;i<n;i++)
            scanf("%d%d",&pos[i],&val[i]);
        build(1, n ,1);
        for(i=n-1;i>=0;i--)
            update(pos[i]+1, val[i], 1, n, 1);
        print(1, n, 1);
        printf("\n");
    }
    return 0;
}

还有一种是节点记录已占有的位置(即非空位),cnt[rt]+pos<=m访问左节点,否则就访问右儿子(访问右儿子时节点修改为cnt[rt]+pos);

View Code
#include<stdio.h>
#include<string.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define mid int m = (l + r)>>1
#define maxn 200000
int cnt[maxn<<2],ans[maxn<<2],pos[maxn],val[maxn];
void update(int pos, int val, int l, int r, int rt)
{
    cnt[rt]++;
    if(l == r){ans[rt]=val;return;}
    mid;
    if(pos + cnt[rt<<1] <= m)update(pos, val, lson);
    else update(pos+cnt[rt<<1], val, rson);
}
void print(int l, int r, int rt)
{
    if(l == r){printf("%d ",ans[rt]);return;}
    mid;
    print(lson);
    print(rson);
}
int main()
{
    int n,i;
    while(~scanf("%d",&n))
    {
        memset(cnt,0,sizeof(cnt));
        for(i=0;i<n;i++)
            scanf("%d%d",&pos[i],&val[i]);
        for(i=n-1;i>=0;i--)
        {
            update(pos[i]+1, val[i], 1, n, 1);
        }
        print(1, n, 1);
        printf("\n");
    }
    return 0;
}

 

 

posted @ 2012-07-11 18:29  To be an ACMan  Views(3611)  Comments(0Edit  收藏  举报