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]);

    }

}

 

你可能感兴趣的:(poj)