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

  • 相关阅读:
    【BZOJ5286】[HNOI2018]转盘(线段树)
    【BZOJ2003】[HNOI2010]矩阵(搜索)
    【BZOJ2000】[HNOI2000]取石头游戏(贪心,博弈论)
    【BZOJ1998】[HNOI2010]物品调度(并查集,模拟)
    【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)
    【BZOJ1925】[SDOI2010]地精部落(动态规划)
    【BZOJ1856】[SCOI2010]字符串(组合数学)
    【BZOJ1826】[JSOI2010]缓存交换(贪心)
    【BZOJ1823】[JSOI2010]满汉全席(2-sat)
    【BZOJ1822】[JSOI2010]冷冻波(二分,网络流)
  • 原文地址:https://www.cnblogs.com/Griselda/p/2720481.html
Copyright © 2020-2023  润新知