首页 > 其他分享 >懒标记线段树

懒标记线段树

时间:2023-07-27 17:56:44浏览次数:35  
标签:lazy 标记 int 线段 self data 节点 def

1. 操作

符号 含义
\(nums\) 原数组
\(d\) 线段树节点维护值
\(lazytag\) 线段树节点懒标记值
\(p\) 当前节点
\(s\) 查询区间的开始
\(e\) 查询区间的结尾
\(l\) 节点区间的开始
\(r\) 节点区间的结尾
  • 一般习惯:
    • 建树从下标 \(1\) 开始
    • \(mid = (l + r) >> 1\)

2. 建立线段树

以 \(nums = \{1,2,3\}\) 为例子,首先是提供的 api ,伪代码如下所示。对于一个节点,我们从根节点开始,递归构造整个树到叶子节点,并且从叶子节点 \(pushup\) 到根节点。对于一个节点:

  • 若当前是叶子节点,即 \(s=e\) ,那么 \(d_{p} = nums_{p}\)
  • 若当前的节点是非叶子节点,即 \(s < e\) ,那么将区间分割为两个部分即 \([s, mid]\) 和 \([mid + 1, l]\) , 递归到左右两个孩子进行建树。
void pushup(int p){
	d[p] = d[p << 1] + d[(p << 1) | 1];
}
void build(int s, int e, int p){
	if (s == e){
		d[p] = nums[p];
		return;
	}
	int mid = (s + e) >> 1;
	build(s, mid, p << 1);
	build(mid + 1, e, (p << 1) | 1);
	pushup(p);
}

3. 区间查询

对于一个节点,其存储的是 \([l, r]\) 区间内维护的值,而对于一个区间查询 \([s, e]\) ,若有查询区间 \([s, e]\) 完全覆盖当前节点区间 \([l, r]\) 即 \(s\leq l\) 且 \(r\leq e\) 查询的值即为 \(d_{p}\) 。否则,区间将一分为二,在分别查询。

  • \([l, mid]\) 左儿子对应的下标为 \(p << 1\)
  • \([mid + 1, r]\) 右儿子的对应下标为 \((p << 1) | 1\)
    如果每一次更新区间值,都会使得整个线段树向下更新到根节点。在区间更新的时候应该使用懒标记线段树,延迟整个节点的信息更新。
    带懒标记的线段树,实际上是父节点暂时记录了下推到子节点的信息。在查询时,才将延迟更新的节点信息加载到子节点。
int query(int l, int r, int s, int e, int p){
	if (l >= s and r <= e){
		return  d[p];
	}
	auto pushdown = [&](int p){
		if (lazy[p]){
			d[p << 1] += lazy[p] * (mid - s + 1);
			d[(p << 1) | 1] += lazy[p] * (e - mid);
			lazy[p << 1] += lazy[p];
			lazy[(p << 1) | 1] += lazy[p];
		}
		lazy[p] = 0;
	};
	pushdown(p);
	int mid = (s + e) >> 1;
	int ret = 0;
	if (s <= mid){
		ret += query(l, r, s, mid, p << 1);
	}
	if (l >= mid){
		ret += query(l, r, mid, l, (p << 1) | 1);
	}
	return ret;
}

4.区间修改

区间修改的过程是产生新的懒标记,而区间查询是将懒标记向下传递。

void modify(int l, int r, int x, int s, int e, int p){
	if (l <= s and r >= e){
		d[p] += (e - s + 1) * x;
		lazy[p] += x;
		return;
	}
	int mid = (s + e) >> 1;
	pushdown(p);
	if (s <= mid){
		modify(l, r, x, s, mid, p << 1);
	}
	if (e >= mid){
		modify(l, r, x, mid, e, (p << 1) | 1);
	}
	d[p] = d[p << 1] + d[(p << 1) | 1];
}

更新数组后处理求和查询

  • 每个节点存储区间求和值和区间长度即可。
class LazySegmentTree:
    __slots__ = ["op_X", "e_X", "mapping", "compose", "id_M", "N", "log", "N0", "data", "lazy"]

    def __init__(self, op_X, e_X, mapping, compose, id_M, N, array=None):
        self.e_X = e_X
        self.op_X = op_X
        self.mapping = mapping
        self.compose = compose
        self.id_M = id_M
        self.N = N
        self.log = (N - 1).bit_length()
        self.N0 = 1 << self.log
        self.data = [e_X] * (2 * self.N0)
        self.lazy = [id_M] * self.N0
        if array is not None:
            assert N == len(array)
            self.data[self.N0:self.N0 + self.N] = array
            for i in range(self.N0 - 1, 0, -1):
                self.update(i)

    def Set(self, p, x):
        assert 0 <= p < self.N
        p += self.N0
        for i in range(self.log, 0, -1):
            self.push(p >> i)
        self.data[p] = x
        for i in range(1, self.log + 1):
            self.update(p >> i)
    
    def prod(self, l, r):
        if l == r: return self.e_X
        l += self.N0
        r += self.N0
        for i in range(self.log, 0, -1):
            if (l >> i) << i != l:
                self.push(l >> i)
            if (r >> i) << i != r:
                self.push(r >> i)

        sml = smr = self.e_X
        while l < r:
            if l & 1:
                sml = self.op_X(sml, self.data[l])
                l += 1
            if r & 1:
                r -= 1
                smr = self.op_X(self.data[r], smr)
            l >>= 1
            r >>= 1
        return self.op_X(sml, smr)

    def all_prod(self):
        return self.data[1]

    def apply(self, p, f):
        p += self.N0
        for i in range(self.log, 0, -1):
            self.push(p >> i)
        self.data[p] = self.mapping(f, self.data[p])
        for i in range(1, self.log + 1):
            self.update(p >> i)

    def apply(self, l, r, f):
        if l == r: return
        l += self.N0
        r += self.N0
        for i in range(self.log, 0, -1):
            if (l >> i) << i != l:
                self.push(l >> i)
            if (r >> i) << i != r:
                self.push((r - 1) >> i)

        l2, r2 = l, r
        while l < r:
            if l & 1:
                self.all_apply(l, f)
                l += 1
            if r & 1:
                r -= 1
                self.all_apply(r, f)
            l >>= 1
            r >>= 1

        l, r = l2, r2
        for i in range(1, self.log + 1):
            if (l >> i) << i != l:
                self.update(l >> i)
            if (r >> i) << i != r:
                self.update((r - 1) >> i)


    def update(self, k):
        self.data[k] = self.op_X(self.data[2 * k], self.data[2 * k + 1])

    def all_apply(self, k, f):
        self.data[k] = self.mapping(f, self.data[k])
        if k < self.N0:
            self.lazy[k] = self.compose(f, self.lazy[k])

    def push(self, k): 
        if self.lazy[k] is self.id_M: return
        self.data[2 * k] = self.mapping(self.lazy[k], self.data[2 * k])
        self.data[2 * k + 1] = self.mapping(self.lazy[k], self.data[2 * k + 1])
        if 2 * k < self.N0:
            self.lazy[2 * k] = self.compose(self.lazy[k], self.lazy[2 * k])
            self.lazy[2 * k + 1] = self.compose(self.lazy[k], self.lazy[2 * k + 1])
        self.lazy[k] = self.id_M

e_X = [0, 0]
id_M = 0

def op_X(X, Y):
    return [X[0] + Y[0], X[1] + Y[1]]

def compose(f, g):
    return f ^ g

def mapping(f, X):
    if f == 1:
        X[0] = X[1] - X[0]
    return X

class Solution:
    def handleQuery(self, nums1: List[int], nums2: List[int], queries: List[List[int]]) -> List[int]:
        n = len(nums1)
        nums1 = [[x, 1] for x in nums1]
        st = LazySegmentTree(op_X, e_X, mapping, compose, id_M, n, nums1)
        s = sum(nums2)
        ans = []
        for idx, a, b in queries:
            if idx == 1:
                st.apply(a, b + 1, 1)
            elif idx == 2:
                s += st.all_prod()[0] * a
            else:
                ans.append(s)
        return ans

标签:lazy,标记,int,线段,self,data,节点,def
From: https://www.cnblogs.com/wasser007/p/17585675.html

相关文章

  • poj 2886 Who Gets the Most Candies? (线段树单点更新应用)
                           poj2886WhoGetstheMostCandies?DescriptionNchildrenaresittinginacircletoplayagame.Thechildrenarenumberedfrom1toNinclockwiseorder.Eachofthemhasacardwithanon-zerointegeronit......
  • uva 12299 RMQ with Shifts(线段树单点更新初步应用)
                                 uva12299RMQwithShiftsInthetraditionalRMQ(RangeMinimumQuery)problem,wehaveastaticarrayA.Thenforeachquery(L,R)(LR),wereporttheminimumvalueamongA[L],A[L+1],...,A[R].N......
  • 线段树解题技巧
    前言线段树是一种在\(\log\)时间内维护区间信息的数据结构,其维护的信息通常具有区间可加性。区间可加性,也就是由区间\(A\)和区间\(B\),可以推出\(A\cupB\)。上面说到的区间,指的是区间内维护的信息。如区间和,区间平方和,区间最值,区间最大子段,区间最长连续子段,这类问题就是......
  • 学不会的线段树
    前言(胡言乱语)“杭电杯”被狠狠薄纱......
  • P3352 [ZJOI2016] 线段树 思考--zhengjun
    有一个显然的\(O(n^3q)\)的做法:设\(f_{i,l,r,x}\)表示\(i\)次操作过后,区间\([l,r]\)的数\(\lex\),\(a_{l-1},a_{r+1}>x\)的方案数。转移:$$f_{i,l,r,x}=f_{i-1,l,r,x}\timesg_{l,r}+\sum\limits_{j<l}f_{i-1,j,r,x}\times(j-1)+\sum\limits_{j>r}f_{i-1,l......
  • 线段树
    //单点修改查询//http://ybt.ssoier.cn:8088/problem_show.php?pid=1549//https://www.luogu.com.cn/problem/P1198//用一维数组来存,当作完全二叉树来存#include<bits/stdc++.h>usingnamespacestd;constintN=2e5+10;longlongintm,p,n,last,t;charop;structnod......
  • 【codevs3012】线段覆盖4
      #include<iostream>#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;structhp{ intai,bi,ci;}a[1005];boolcmp(hpa,hpb){ returna.bi<b.bi;}constintM=1e6+2;intn,i,j,k,maxn,f[1005];int......
  • 【模板】线段树优化建图
    区间连区间luoguP6348[PA2011]Journeys略带卡常#include<bits/stdc++.h>usingnamespacestd;vector<pair<int,int>>e[4200001];intdis[4200001],id[4200001];intlson(intl){returnl*2;}intrson(intl){returnl*2+1;}voidbuild(int......
  • 洛谷 P8861 - 线段
    牛逼题。先考虑\(l\le10^5,10^5+1\ler\)的部分分:一种方法是线段树,即因为左右端点是独立的,因此对左右端点各维护一个权值线段树表示有多少个区间以这个值为左/右端点,这样对于修改,左端点的部分相当于先查询\(\lel\)的数的个数,然后将它们都挂到\(l\)上,最后把\(<l\)的部......
  • 线段树--区间最大值模板
    Smiling&Weeping----你是我绕过的山河错落,才找到的人间烟火ProblemDescriptionThereisasequence a oflength n.Weuse ai todenotethe i-thelementinthissequence.Youshoulddothefollowingthreetypesofoperationstoth......