POJ2828线段树单点更新——逆序更新

Description
输入n个有序对< pi, vi >,pi表示在第pi个位置后面插入一个值为vi的人,并且pi是不降的。输出最终得到的v的序列
Input
多组用例,每组用例第一行为有序对组数n,之后n行每行两个整数表示一个有序对,以n=0结束输入
Output
对于每组用例,输出最后得到的序列
Sample Input
4
0 77
1 51
1 33
2 69
4
0 20523
1 19243
1 3890
0 31492
Sample Output
77 33 69 51
31492 20523 3890 19243

单点插入线段树——所以建树的时候叶子节点应该为大于n的第一个数(cnt = 2 ^ k  > n)

建树的时候我们logn找到该点向下更新叶子和向上更新根节点特别的我们要记录这个节点还有多少空位

为什么要逆序?

因为最后的元素可以确定位置,而忽略前面元素的影响

例如 0 10 0 11

我们逆序来插入值     11   ?

?代表还有空

11插入后,那个节点记录表示空位是0

所以插入0 10的时候会通过判断来往?的位置走~

差不多,自己手想一下就好

void build()
{
    int s;
    for(s = 1;s < n;s <<= 1);
    //之所以要出来大于n画一画就好了,n那一层就算没有占满,也要开一层下面的吧

    for(int i = s;i < 2 * s;i++)//叶子
    {
        tree[i].l = tree[i].r = i - s + 1;
        tree[i].cnt = 1;
    }

    for(int i = s-1;i >= 1;i--)//根
    {
        tree[i].l = tree[2*i].l;
        tree[i].r = tree[2*i+1].r;
        tree[i].cnt = tree[2*i].cnt + tree[2*i+1].cnt;
    }
}

 这是第一种建树,也可以常规来

void build(int rt, int left, int right)
{
    tree[rt].l = left;
    tree[rt].r = right;
    tree[rt].cnt = right - left + 1;
    if(left == right)
        return;
    int mid = (left + right) >> 1;
    build(rt<<1,left,mid);
    build(rt<<1|1,mid + 1,right);
}

 code......

//****单点更新线段树
#include <cstdio>
#include <algorithm>
#include <string.h>
#define inf (1 << 29)
using namespace std;
const int maxn = 2e5 + 100;
struct node
{
    int pos;
    int num;
}p[maxn];
struct node2{
    int l,r,cnt;
}tree[maxn << 2];
int n,ans[maxn];
void build(int rt, int left, int right)
{
    tree[rt].l = left;
    tree[rt].r = right;
    tree[rt].cnt = right - left + 1;
    if(left == right)
        return;
    int mid = (left + right) >> 1;
    build(rt<<1,left,mid);
    build(rt<<1|1,mid + 1,right);
}
/*void build()
{
    int s;
    for(s = 1;s < n;s <<= 1);
    //之所以要出来大于n画一画就好了,n那一层就算没有占满,也要开一层下面的吧

    for(int i = s;i < 2 * s;i++)//叶子
    {
        tree[i].l = tree[i].r = i - s + 1;
        tree[i].cnt = 1;
    }

    for(int i = s-1;i >= 1;i--)//根
    {
        tree[i].l = tree[2*i].l;
        tree[i].r = tree[2*i+1].r;
        tree[i].cnt = tree[2*i].cnt + tree[2*i+1].cnt;
    }
}*/
void insertpoint(int i,int pos,int num)
{
    if(tree[i].l == tree[i].r)
    {
        ans[tree[i].l] = num;
        tree[i].cnt = 0;
        return;
    }

    if(pos <= tree[2*i].cnt)
        insertpoint(2*i,pos,num);
    else
        insertpoint(2*i+1,pos - tree[2*i].cnt,num);
    tree[i].cnt--;
}
int main()
{
    while(~scanf("%d",&n))
    {
        int k = 0;
        for(k = 1;k < n;k <<= 1);
        build(1,1,k);
        for(int i = 0;i < n;++i)
            scanf("%d%d",&p[i].pos,&p[i].num);
        for(int i = n - 1;i >= 0;i--)
            insertpoint(1,p[i].pos + 1,p[i].num);
        for(int i = 1;i <= n;i++)
        {
            printf("%d%c",ans[i],i == n ? '\n' : ' ');
        }
    }

    return 0;

}

 

posted @ 2018-08-08 14:45  Butterflier  阅读(130)  评论(0编辑  收藏  举报