poj 2828 线段树

http://poj.org/problem?id=2828

学到的思维:

1、变化的或者后来的优先影响前面的,那么从最后一个往前看,最后一个就成了 确定的, 并且后来的也可以确定----如果从前往后,所有的随时都不是确定的

2、线段树叶子节点直接维护区间(线段)信息,非叶子节点v维护的是以v为树根的整个子树的信息,那么假设父节点rt信息为[l,r]那么左子树维护[l,mid],右子树维护[mid+1,r]的信息。如果如果是前缀和,rt里是1-n的和,左子树1~n/2的和,右子树是n/2+1~n的和,

3、前两点想明白之后就能1A了

cnt是当前结点l~r中所有空位,这时候,认真想会发现,输入中的“次序的值”可以当做空位的个数,更新的时候,根据左右子树中的空位树有没有达到要插入的值的"次叙数",就可以确定进入左子树或者右子树。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int MAXN = 200000 +10;

int num[MAXN],pos[MAXN],ans[MAXN];

struct Node{
    int l,r;
    int cnt;//r前面还有几个空位,最初l,l+1...r-1
}nodes[MAXN*4];

void build(int rt, int l, int r)
{
    nodes[rt].l=l;
    nodes[rt].r=r;
    nodes[rt].cnt=r-l+1;
    if(l == r)
    {
        ans[l]=0;//
        return;
    }
    int mid=(l+r)/2;
    build(rt*2, l,mid);
    build(rt*2+1, mid+1, r);
}

void update(int rt, int p, int v)
{
    nodes[rt].cnt--;
    if(nodes[rt].l == nodes[rt].r)
    {
        //nodes[rt].cnt--;
        ans[nodes[rt].l]=v;
        return ;
    }
    if(p<=nodes[rt*2].cnt)update(rt*2, p, v);
    else update(rt*2+1, p-nodes[rt*2].cnt, v);
    nodes[rt].cnt=nodes[rt*2].cnt+nodes[rt*2+1].cnt;
}

int main()
{
    //freopen("poj2828.txt","r",stdin);
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d",&pos[i],&num[i]);
        build(1,1,n);
        for(int i=n;i>0;i--)
        {
            update(1,pos[i]+1,num[i]);
        }
        for(int i=1;i<n;i++)
            printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
    }
    return 0;

}

poj 2828 线段树

时间: 2024-08-24 07:12:27

poj 2828 线段树的相关文章

poj 2828(线段树 逆向思考) 插队是不好的行为

http://poj.org/problem?id=2828 插队问题,n个人,下面n行每行a,b表示这个人插在第a个人的后面和这个人的编号为b,最后输出队伍的情况 涉及到节点的问题可以用到线段树,这里因为每个人插队时有顺序的,如果按照正着的顺序来情况太复杂,所以可以试试倒过来,从最后一个人开始,此时找到的位置 一定是最终位置,这样就很简单了,   结构体中多开一个mark表示每个区间的空位置,多开一个sum表示人的编号 这道题不错,提醒我们有时候换一换思路,逆向思考一下 1 #include<

poj 2828(线段树单点更新)

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 18561   Accepted: 9209 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue… The Lunar New Year wa

POJ 2828 线段树(想法)

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 15422   Accepted: 7684 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue… The Lunar New Year wa

poj 2828 线段树插孔处理

给你一个数列出现的先后顺序num[i]和对应数值   输出最后排好序的对应数值,如 4 0 77 1 51 1 33 2 69 第一步  77 第二部 77  51 第三步 77  33 51 第四部77  33  69 51 后面先出现的位置是固定的  所以从后往前处理. 线段树每个节点存当前区间还有多少个空位: #include<stdio.h> #include<string.h> #include<iostream> using namespace std; #

POJ 2828 (线段树 单点更新) Buy Tickets

倒着插,倒着插,这道题是倒着插! 想一下如果 Posi 里面有若干个0,那么排在最前面的一定是最后一个0. 从后往前看,对于第i个数,就应该插在第Posi + 1个空位上,所以用线段树来维护区间空位的个数. 说一下那个坑爹的第56行的判断: if(i > 1) printf(" "); 将输出的n个数用空格隔开,我感觉这是一个还算常用的写法啊,结果各种莫名TLE,加上输入挂也补救不回来. 去掉这个无谓的判断后,3594MS险过,加上输入挂3094MS,还算是起到了一定的加速作用.

POJ 2828 线段树应用

这道题是之前一场比赛碰到的题目,当时看到题时以为是一道用链表优化的水题,交了几遍一直超时,简直不能再感人(┬_┬)今天有空突然想起去查了下题解,是用线段树做的.....完全想不到啊有木有~思路大概就是每个节点存当前节点下还剩多少空位,然后倒序查找该人所需要的位置,具体细节看代码吧. Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 15801   Accepted: 7876 Description

Buy Tickets POJ - 2828线段树求插队

题意就是给你n个人,每个人有自己的要插入的pos和val,问你最后的排序 思路:逆序插入,最后一个人的位置一定是固定的,因为必须连续插入,所以第i个人插入的时候必须保证前面有pos[i]个空位, 那么用线段树记录位置个数,如果位置不够,就往后挪. #include<iostream> #include<cstdio> using namespace std; #define N 200005 int spare[N<<2]; int seq[N]; int pos[N]

POJ 2828 线段树单点更新 离线搞

Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he ha

POJ 2528 (线段树+离散化) Mayor&#39;s posters

因为将每个单位都作为一个最小单元的话会爆内存的 所以,将海报的每个端点进行排序,将这些端点最为最小的区间. 毕竟是刚刚接触线段树,理解起来还有些吃力,还是那句话,题做多了慢慢就好了. 萌萌的AC代码君贴上. 1 //#define LOCAL 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 int n; 8 struct CPost 9