POJ2828

题意:有n个的排队,每一个人都有一个val来对应,每一个后来人都会插入当前队伍的某一个位置pos。要求把队伍最后的状态输出。

逆向思维。我们可以这样考虑,最后一个人一定会得到当前队伍他想要的位置,如果我们往前一个阶段,倒数第二个人也一定能得到他想要的位置……,也就是说,我们可以这样处理,我们把最后一个人插入,然后忽略它,再把倒数第二个人插入。即,我们找出当前队伍他想要插入的位置pos的真正坐标就可以。然后去更新整个队伍的长度。如此循环,直到最后一个人。线段树在单点更新的时候,感觉和二分查找是很相似的,可以用它实现。

#include <iostream>  
#include <cstdio>  
using namespace std;  
const int N=200005;  
int y[N];  
struct Per  
{  
    int pos,val;  
}per[N];  
struct node  
{  
    int left,right,cnt;  
    int mid()
    {
        return left+(right-left)/2;
    }  
    int dis()
    {
        return right-left+1;
    }  
};  
struct Segtree  
{  
    node tree[N*4];  
    void build(int left,int right,int r)  
    {  
        tree[r].left=left;  tree[r].right=right;  
        tree[r].cnt=tree[r].dis();  
        if(left<right)  
        {  
            int mid=tree[r].mid();  
            build(left,mid,r*2);  
            build(mid+1,right,r*2+1);  
        }  
    }  
    int query(int pos,int r)  
    {  
        tree[r].cnt--;  
        if(tree[r].left==tree[r].right) return tree[r].left;  
        else  
        {  
            if(pos<tree[r*2].cnt) return query(pos,r*2);  
            else return query(pos-tree[r*2].cnt,r*2+1);  
        }  
    }  
}seg;  
int main()  
{  
    int n;  
    while(scanf("%d",&n)!=EOF)  
    {  
        for(int i=0;i<n;i++) 
            scanf("%d%d",&per[i].pos,&per[i].val);  
        seg.build(0,n-1,1);  
        for(int i=n-1;i>=0;i--)  
        {  
            int pos=seg.query(per[i].pos,1);  
            y[pos]=per[i].val;  
        }  
        for(int i=0;i<n;i++)  
        {  
            if(i!=0) 
                putchar(' ');  
            printf("%d",y[i]);  
        }  
        puts("");  
    }  
    return 0;  
}  


你可能感兴趣的:(POJ2828)