您的位置:首页 > 其它

buy tickrt(线段树)单点更新应用变形

2016-12-11 13:31 232 查看
这个题应该代码不是很难,而对于代码的理解,如何将题目转化为线段树的思路进行更新是一个难点,还有就是树 的结构体里面存放什么内容!!!!

线段树,是将暴力遍历更新高效化的一个重要方法,尤其关系某相邻几项的关联之间

难点一:从主函数来看,它是将数据逆序更新,why

               如果正序更新的话,赋值的很容易,但是你如果有重复的位置,每次都要通过On的暴力复杂度对其向后推移,很容易TLE,所有如果通过逆序进行,最后一个的位置是               不变的,为前n-1个数字通过其发生改变(预知如何改变,且听下面的难点分析)

难点二:既然是树,线段树一遍是与结构体相结合,那么在结构体的val变量中放什么呢

               我首先想到的是,该位置若以填满为0,没有填的时候为1。然后我就蒙了,这是要通过判断他是否为1来更新吗?如果是这样的话,每次也就需要每次都要往后的推移                  的时候挨个判断是否可以赋值,如果后面的填满的很多的话,一样是On 的暴力

               然后我就通过看题解找到答案,将树 的结构体变量里面放sum为从l到r的空位数,未填的个数,如果pos【i】+1输入时判断是否有正好第p个空位来村正数,前p-1个                    ,因为如果已填数的位置sum被更新,不算在内。这样就能找到那个要放到位置了

难点二:如何更新呢

               难点二吧吧答题的意思都说明白了,那么如何更新呢

              当正好有n个空位,与pos【i】+1相符,那么这个位置就应该是要找到的那个位置了,那么当这个位置他滋生这个数的位置被占了的时候,回向后推移,也就是这样的话会存在左子树不足的情况(空位数不足),那么我们将在其右子树里面寻找,因为我们要放在第pos【i】+1空位上吗’,那么就通过sum和寻找,所以当进去右子树时,需要的是出去前面左子树中的(从第一位开始)所以需要前去前边的空格数,从右子树 的数开始

所以另外一个很重要的难点就是看出要放在第i个空位的问题

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 had to travel by train to Mianyang, Sichuan Province for the winter camp selection of the national team of Olympiad in Informatics.

It was one o’clock a.m. and dark outside. Chill wind from the northwest did not scare off the people in the queue. The cold night gave the Little Cat a shiver. Why not find a problem to think about? That was none the less better than freezing to death!

People kept jumping the queue. Since it was too dark around, such moves would not be discovered even by the people adjacent to the queue-jumpers. “If every person in the queue is assigned an integral value and all the information about those who have jumped
the queue and where they stand after queue-jumping is given, can I find out the final order of people in the queue?” Thought the Little Cat.

Input

There will be several test cases in the input. Each test case consists of N + 1 lines where N (1 ≤ N ≤ 200,000) is given in the first line of the test case. The next N lines contain the pairs of values Posi and Vali in
the increasing order of i(1 ≤ i ≤ N). For each i, the ranges and meanings of Posi and Vali are as follows:

Posi ∈ [0, i − 1] — The i-th person came to the queue and stood right behind the Posi-th person in the queue. The booking office was considered the 0th person and the person at the front of the queue
was considered the first person in the queue.
Vali ∈ [0, 32767] — The i-th person was assigned the value Vali.
There no blank lines between test cases. Proceed to the end of input.

Output

For each test cases, output a single line of space-separated integers which are the values of people in the order they stand in the queue.

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


Hint

The figure below shows how the Little Cat found out the final order of people in the queue described in the first test case of the sample input.




#7715209 zhuyinghui's solution for [POJ-2828] [Problem
F]


StatusAccepted
Time3735ms
Memory9184kB
Length1296
LangG++
Submitted2016-12-11 13:29:45
Shared
RemoteRunId16382367
Select Code
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 200020
using namespace std;

struct node
{
int l,r,sum;
}tree[maxn<<2];
int ans[maxn];

void build(int rt,int p,int q)
{
tree[rt].l=p;
tree[rt].r=q;
if(p==q)
{
tree[rt].sum=1;
return ;
}
build(rt<<1,p,(p+q)/2);
build(rt<<1|1,(p+q)/2+1,q);
tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}

void update(int rt,int navl,int val)
{
if(tree[rt].l==tree[rt].r)
{
tree[rt].sum=0;
ans[tree[rt].l]=val;
return ;
}
if(tree[rt<<1].sum>=navl)
update(rt<<1,navl,val);
else
update(rt<<1|1,navl-tree[rt<<1].sum,val);  //此处说说p-tree[rt].sum 的问题,我们用sum表示从该段的空位数,当空位数被填满是也就是上一层中对空位数的判断表示该数要放在第p个位置(不包括已填满的,就是空位数,已填满的地方的sum=0,数字变小)所以当第p个位置要放是需要减去前边几个空位数凑数))
tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}

int main()
{
int n;
int pos[maxn],num[maxn];
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("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树 单点更新