[hiho 20]线段树的区间修改

题目描述

区间修改有别于单点修改,如果每次都修改到叶子节点,复杂度可以退化到O(n)。

因此为节点引入一个lazy标记,修改时,如果待修改区间与某个节点的区间重合,那么这个节点更新值后标记lazy,不再修改其子节点。

类似于查询操作,这个修改操作的复杂度是O(logn)。

另外,查询或修改时,如果遇到已经标记了lazy的节点,需要先将lazy标记下放到两个子节点,再进行后续处理。

#include <stdio.h>
#include <algorithm>

typedef
struct _seg_tree_ {
    int left, right;
    int val;
    bool lazy_tag;
    _seg_tree_ *lson = NULL, *rson = NULL;
    _seg_tree_(int left_idx, int right_idx, int value)
        : left(left_idx), right(right_idx), val(value), lazy_tag(false) {}
} seg_tree, *pseg_tree;

pseg_tree construct_seg_tree(int left, int right) {
    if (left == right) {
        int val;
        scanf("%d", &val);
        return new seg_tree(left, left, val);
    }
    int mid = left + (right - left) / 2;
    pseg_tree lson = construct_seg_tree(left, mid);
    pseg_tree rson = construct_seg_tree(mid + 1, right);
    int val = lson->val + rson->val;
    pseg_tree ans = new seg_tree(left, right, val);
    ans->lson = lson;
    ans->rson = rson;
    return ans;
}

void lazy_down(pseg_tree proot) {
    int mid = proot->left + (proot->right - proot->left) / 2;
    proot->lazy_tag = false;
    int x = proot->val / (proot->right - proot->left + 1);
    proot->lson->lazy_tag = true;
    proot->lson->val = x * (mid - proot->lson->left + 1);
    proot->rson->lazy_tag = true;
    proot->rson->val = x * (proot->rson->right - mid);
}

int query_seg_tree(pseg_tree proot, int left, int right) {
    if (left == proot->left && right == proot->right) {
        return proot->val;
    }

    int mid = proot->left + (proot->right - proot->left) / 2;
    if (proot->lazy_tag == true) {
        lazy_down(proot);
    }
    if (left > mid) {
        return query_seg_tree(proot->rson, left, right);
    }
    if (right <= mid) {
        return query_seg_tree(proot->lson, left, right);
    }
    return query_seg_tree(proot->lson, left, mid)
        + query_seg_tree(proot->rson, mid + 1, right);
}

void modify_seg_tree(pseg_tree proot, int left, int right, int val) {
    if (left == proot->left && right == proot->right) {
        proot->val = val * (right - left + 1);
        proot->lazy_tag = true;
        return;
    }
    int mid = proot->left + (proot->right - proot->left) / 2;
    if (proot->lazy_tag == true) {
        lazy_down(proot);
    }
    if (left > mid) {
        modify_seg_tree(proot->rson, left, right, val);
    }
    else if (right <= mid) {
        modify_seg_tree(proot->lson, left, right, val);
    }
    else {
        modify_seg_tree(proot->rson, mid + 1, right, val);
        modify_seg_tree(proot->lson, left, mid, val);
    }
    proot->val = proot->lson->val + proot->rson->val;
}

int main(){
    int n, q;
    scanf("%d", &n);
    pseg_tree proot = construct_seg_tree(1, n);
    scanf("%d", &q);
    int op, left, right, value;
    while (q--) {
        scanf("%d%d%d", &op, &left, &right);
        if (op == 0) {
            int ans = query_seg_tree(proot, left, right);
            printf("%d\n", ans);
        } else {
            scanf("%d", &value);
            modify_seg_tree(proot, left, right, value);
        }
    }

    return 0;
}
时间: 2024-11-09 23:15:54

[hiho 20]线段树的区间修改的相关文章

hiho一下20周 线段树的区间修改

线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho: 假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi.小Hi的每次操作分为两种可能,第一种是修改价格--小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP.第二种操作是询问--小Hi给出一段区间[L, R]

hihoCoder #1078 : 线段树的区间修改(线段树区间更新板子题)

#1078 : 线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho: 假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi.小Hi的每次操作分为两种可能,第一种是修改价格——小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP.第二种操作是询问——小Hi给出一段

poj 3468:A Simple Problem with Integers(线段树,区间修改求和)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 58269   Accepted: 17753 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

模板 线段树的区间修改

线段树的区间修改 区间绝对标记 改成同一个数 注意打标记前 要先判断 是否有标记 这道题不能像加法标记一样 标记初始化为 0 如果这道题 可以将数变成 0 那么0 就不能为初始值了 然后我们初始值要选择一个不会被干扰到的数字 比如 -1 就不会变成 -1 另外还要注意在标记清空时 要将标记 变成 -1 而不是 0 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstr

hihoCode 1078 : 线段树的区间修改

#1078 : 线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho: 假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi.小Hi的每次操作分为两种可能,第一种是修改价格——小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP.第二种操作是询问——小Hi给出一段

线段树的区间修改

线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho: 假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi.小Hi的每次操作分为两种可能,第一种是修改价格--小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP.第二种操作是询问--小Hi给出一段区间[L, R]

POJ 2828 Buy Tickets (线段树,区间修改)

逆向思维.从最后一位开始考虑,用线段树查询空位置. #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include &l

培训补坑(day7:线段树的区间修改与运用)(day6是测试,测试题解以后补坑QAQ)

补坑咯~ 今天围绕的是一个神奇的数据结构:线段树.(感觉叫做区间树也挺科学的.) 线段树,顾名思义就是用来查找一段区间内的最大值,最小值,区间和等等元素. 那么这个线段树有什么优势呢? 比如我们要多次查询1-n中的最大值,那么我们如果使用暴力来查找,那么我们每次查找的复杂度就是O(n) 但是如果我们把一个个区间变成树上的一个个点,并且我们严格保证树的深度,那么我们每次查找的复杂度就是O(logn) 这样就能让查询变得更快. 我们先简单讲一下线段树的存储(图中的标号就是线段树数组标号) 这就是线段

HZAU 1207 Candies(线段树区间查询 区间修改)

[题目链接]http://acm.hzau.edu.cn/problem.php?id=1207 [题意]给你一个字符串,然后两种操作:1,将区间L,R更新为A或者B,2,询问区间L,R最长的连续的B为多长. [分析]典型线段树,每个节点维护该区间左边连续B的长度,右边连续B的长度,最长的连续B的长度,还有lazy标记. #include <cstdio> #include <cstring> #include <iostream> #include <algor