POJ 2828 tickets 【线段树 基础 单点更新】.cpp ※ 线段树基础总结

题意:

  给出一些人要求插入队列的位置和他们的身高

  输出最后队列的每个人身高

 

输入:

  给出n 表示有n个人

  给出每个人要插进的队列的位置和该人的身高

 

思路:

  sum 数组保存该区间的空位

  a 数组保存该位置的人的身高

  pushup函数用来自下向上更新区间空位

  modify函数用来根据sum值找出空位并插入..

 

Tips:

  比较的时候..如果比左节点的sum值大就往右子树插位置..

  所以比较函数写的应该是..if(p <= sum[rt<<1])

  往右子树插的时候传入的参数也应该相应减少..即p - sum[rt<<1]

 

Code:

View Code
 1 //模拟链表 数据量太大..遍历会超时..
 2 #include <stdio.h>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 const int MAXN = 200010;
 7 int a[MAXN], sum[MAXN<<2];
 8 
 9 struct P
10 {
11     int key;
12     int val;
13 }pp[MAXN];
14 
15 void pushup(int rt)
16 {
17     sum[rt] = sum[rt<<1]+sum[rt<<1|1];
18 }
19 
20 void creat(int l, int r, int rt)
21 {
22     if(l == r) {
23         sum[rt] = 1;
24         return;
25     }
26     int mid = (l+r)>>1;
27     creat(l, mid, rt<<1);
28     creat(mid+1, r, rt<<1|1);
29     pushup(rt);
30 }
31 
32 void modify(int p, int w, int l, int r, int rt)
33 {
34     if(l == r) {
35         sum[rt]--;
36         a[l] = w;
37         return;
38     }
39     int mid = (l+r)>>1;
40     if(p <= sum[rt<<1]) modify(p, w, l, mid, rt<<1);///!!!
41     else modify(p - sum[rt<<1], w, mid+1, r, rt<<1|1);///!!!
42     pushup(rt);
43 }
44 
45 int main()
46 {
47     int i, j, k;
48     int n, val, key;
49     while(scanf("%d", &n) != EOF)
50     {
51         creat(1, n, 1);
52 
53         for(i = 0; i < n; ++i)
54             scanf("%d %d", &pp[i].key, &pp[i].val);
55 
56         for(i = n-1; i >= 0; --i) {
57             modify(pp[i].key+1, pp[i].val, 1, n, 1);
58         }
59 
60         for(i = 1; i <= n; ++i)
61         printf("%d%c", a[i], i == n?'\n':' ');
62     }
63     return 0;
64 }

 

 

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

 

 

线段树基础总结:

确定四个函数 两个数组

※四个函数

void pushup(int rt)  自下向上更新线段树 sum数组是用来求和呢 还是 求最大值

void creat(int l, int r, int rt) 创建线段树 其中 r 的大小应该以最大可能出现的数的个数为准..

               如果是初始化数组则第一句为初始化数组 第二句为 l == r 就 return

void modify(int p, int w, int l, int r, int rt) 把线段树更新.. 第一条的 if 语句用来更新线段树的叶子节点的值..并进行相关操作..

                      注意比较的时候是和 mid 比较呢还是和sum[rt<<1]比较 即使是根据位置更新节点 还是 根据区间值更新节点..

void query(int l, int r, int L, int R, int rt) 查询线段树某一区间的值..最大值或和..

 

两个数组..

sum 保存线段树节点的值.. 所以要考虑这棵树究竟保留的是什么信息..

a 保存的是叶子节点的相关信息..

 

变形:

①. 求区间和 

②. 求区间最大值

③. 求逆序数(区间求和变形) 根据插入顺序更新sum数组 并且查询从该位置到最后已标记的位置的数量

④. 求一些区间中最大的区间长度(区间最大值变形) 判断的时候应该是和sum[rt << 1] 比较..然后看往哪里更新..

转载于:https://www.cnblogs.com/Griselda/archive/2012/10/11/2720481.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值