POJ 2828 线段树

来源:互联网 发布:网络经济学ppt 编辑:程序博客网 时间:2024/06/14 14:10

题目链接:http://poj.org/problem?id=2828

题意:队列问题,每个人会插入一个位置,每个人有固定id,即val。输出最后队列。

思路:这道题如果正着想会比较难,但是如果考虑从数据末往会考虑就可以发现这个时候序列就已经是固定了的。现在难得就是怎么构建线段树了。考虑每个叶子节点存储一个标志位标志这个位置有没有人,往上的节点存储它的两个儿子中可以放人的个数。查询的时候,如果当前节点p大于左子树可以存储的数量,即p < sum[rt<<1],则访问左子树,意思是把它放在它想放的最靠近的位置,否则访问它的右子树,这时候要考虑迭代的p应该要改变成p-sum[rt<<1]。输出的话,再建立一棵树存储val的值输出就可以了。

#include <iostream>#include <stdio.h>#include <math.h>#include <algorithm>#include <cstring>#include <string>using namespace std;const int maxn = 200005;int a[maxn],val[maxn];int sum[maxn << 2],ans[maxn<<2];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 m = (l + r) >> 1;    build(l, m, rt << 1);    build(m + 1, r, rt << 1 | 1);    PushUp(rt);}void update(int p,int val , int l, int r, int rt){    if (l == r)    {        ans[rt]=val;        sum[rt]=0;        return;    }    int m = (l + r) >> 1;    if (p<=sum[rt<<1]) update(p,val, l, m,   rt << 1);    else update(p-sum[rt<<1],val,  m + 1, r, rt << 1 | 1);//注意p的变更    PushUp(rt);}void pr(int l,int r,int rt){    if(l==r){        printf("%d ",ans[rt]);return;    }    int m=(l+r)>>1;    pr(l,m,rt<<1);    pr(m+1,r,rt<<1|1);}int main(){    int n;    while(~scanf("%d",&n)){        for(int i=0;i<n;i++){            scanf("%d%d",&a[i],&val[i]);        }        build(1,n,1);        for(int i=n-1;i>=0;i--){            update(a[i]+1,val[i],1,n,1);        }        pr(1,n,1);        printf("\n");    }    return 0;}