poj 2828 Buy Tickets

这题没思路,看别人题解

由于最后一个人插进来后他的位置肯定是固定的 我们就可以倒着来插

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

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

Problem: 2828		User: shu_dayang
Memory: 4536K		Time: 1500MS
Language: C++		Result: Accepted



#include<iostream>
#include<cstdio>
#include<cstring>
#define MID(a,b)  ((a + b) >> 1)
using namespace std;

const int MAXN = 200010;

int sum[MAXN << 2],p[MAXN],pos[MAXN],val[MAXN];

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

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

void update(int pos,int val, int l, int r, int rt)
{
    if(l == r)
    {
        p[l] = val;
        sum[rt] --;
        return;
    }
    int mid = MID(l, r);
    if(pos <= sum[rt << 1])
        update(pos, val, l, mid, rt << 1);
    else
        update(pos - sum[rt << 1], val, mid + 1, r, (rt << 1) + 1);
    PushUp(rt);
}

int main()
{
    int n,i;
    while(~scanf("%d",&n))
    {
        build(1,n,1);
        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);

        for(i = 1; i< n ; i++)
            printf("%d ",p[i]);
        printf("%d\n",p[i]);
    }
}

 

posted @ 2015-07-19 12:57  杨永华  阅读(122)  评论(0编辑  收藏  举报