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] 比较..然后看往哪里更新..

你可能感兴趣的:(poj)