• 题解 P2068 【统计和】


    这是一道单点修改,区间查询的线段树。

    需要实现的操作有三个:建树,更新与查询。

    首先,线段树用结构体维护,如下:

    1 struct node {
    2     int l, r;
    3     int val;
    4 } tree[maxn * 4];

    其中l, r表示节点所表示区间左右端点,而val则是区间和。

    Build函数如下:

    1 void Build(int l, int r, int pos) {
    2     tree[pos].l = l;
    3     tree[pos].r = r;
    4     tree[pos].val = 0;
    5     if(l == r) return ;
    6     int mid = (l + r) / 2;
    7     Build(l, mid, pos * 2);
    8     Build(mid + 1, r, pos * 2 + 1);
    9 }

    这个函数就是初始化整棵线段树,没有什么特别需要解释的。

    Update函数如下:

     1 void Update(int x, int val, int pos) {
     2     if(tree[pos].r == tree[pos].l) {
     3         tree[pos].val += val;
     4         return ;
     5     }
     6     
     7     int mid = (tree[pos].l + tree[pos].r) / 2;
     8     if(x <= mid) Update(x, val, pos * 2);
     9     else Update(x, val, pos * 2 + 1);
    10     tree[pos].val = tree[pos * 2].val + tree[pos * 2 + 1].val;
    11 }

    x表示需要修改的节点,val表示需要增加的值,pos表示当前节点。

    如果走到了叶节点上,直接修改,然后结束。

    否则,判断x在当前节点的哪一个儿子上,向下。

    最后更新当前节点的值。

    Query函数如下:

     1 int Query(int l, int r, int pos) {
     2     if(tree[pos].l >= l && tree[pos].r <= r) {
     3         return tree[pos].val;
     4     }
     5     int mid = (tree[pos].l + tree[pos].r) / 2;
     6     int ans = 0;
     7     if(l <= mid) ans += Query(l, r, pos * 2);
     8     if(mid < r) ans += Query(l, r, pos * 2 + 1);
     9     return ans;
    10 }

    如果当前节点的整个区间都已经被包含在所求的区间内了,那么不用再进行划分,返回区间值即可。

    否则分三种情况讨论:

    1. 若所求区间只与左儿子有交集,移到左儿子。

    2. 若只与右儿子有交集,移到右儿子。

    3. 若被当前节点覆盖,左儿子右儿子都算。


    以上就是思路及关键代码。

    顺便推荐两道经典的单点修改题目(反正我是做了的):

    1. HDU1166 敌兵布阵

    2. HDU1754 I hate it

    (注:第二道题是求区间最值,和模板稍有不同。)

  • 相关阅读:
    day38 04-Spring加载配置文件
    day38 03-Spring的IOC和DI的区别
    day38 02-Spring快速入门
    关于mysql-connector-net在C#中的用法
    SQL的四种连接用法整理
    SQL的四种连接用法整理
    SQL的四种连接用法整理
    45道CSS基础面试题
    45道CSS基础面试题
    45道CSS基础面试题
  • 原文地址:https://www.cnblogs.com/ilverene/p/9818989.html
Copyright © 2020-2023  润新知