zoukankan      html  css  js  c++  java
  • 洛谷 P3372 【模板】线段树 1

    洛谷 P3372 【模板】线段树 1

    传送门

    思路

    前几天学了线段树的我,今天又去做了一遍线段树【模板】(1),发现自己打代码真的是漏洞百出啊,不过最后还是对了,所以来水一篇博客

    首先,这道模板题的要求就是:

    1.区间加
    2.区间求和

    这两个操作都属于线段树的基本操作

    前置——宏定义

    #define N 100011
    #define lson rt << 1
    #define rson rt << 1 | 1
    #define int long long
    

    由于我特别懒,不想写什么(rt << 1)之类的东西,所以直接宏定义就好了,还有,为了不改(int),我直接把(int)宏定义为(long long),省的麻烦(我真的是懒到家了)

    1.定义

    int sum[N << 2], lazy[N << 2], n, m;
    

    众所周知,线段树一般要开四倍空间,不明白的可以自己画一颗线段树数一下,sum数组维护区间和,lazy是懒标记

    2.pushup

    inline void pushup(int rt) {
    	sum[rt] = sum[lson] + sum[rson];
    }
    

    这是一个上传给父亲结点的信息的函数,当前节点的区间和就等于它左儿子和右儿子的区间和之和

    2.建树

    void build(int l, int r, int rt) {
    	if(l == r) {
    		sum[rt] = read();
    		return;
    	}
    	int m = (l + r) >> 1;
    	build(l, m, lson);
    	build(m + 1, r, rson);
    	pushup(rt);
    }
    

    上面是建树过程,(rt)表示当前节点,(lson)是左孩子,(rson) 是右孩子

    3.标记下放

    inline void pushdown(int l, int r, int rt) {
    	if(!lazy[rt]) return;
    	lazy[lson] += lazy[rt];
    	lazy[rson] += lazy[rt];
    	int m = (l + r) >> 1;
    	sum[lson] += (m - l + 1) * lazy[rt];
    	sum[rson] += (r - m) * lazy[rt];
    	lazy[rt] = 0;
    	return;
    }
    

    pushdown函数的实现:
    1.用lazy存储这个懒标记。
    2.递归到这个节点时,只更新这个节点的状态,并把当前的更改值累积到标记中。
    什么时候才用到这个懒标记?
    当需要递归这个节点的子节点时,标记下传给子节点。
    3.下放操作:(三步)
    当前节点的懒标记累积到子节点的懒标记中。
    修改子节点状态。
    父节点懒标记清0。

    4.区间修改

    void update(int L, int R, int c, int l, int r, int rt) {
    	if(L <= l && r <= R) {
    		sum[rt] += c * (r - l + 1);
    		lazy[rt] += c;
    		return;
    	}
    	pushdown(l, r, rt);
    	int m = (l + r) >> 1;
    	if(L <= m) update(L, R, c, l, m, lson);
    	if(R > m) update(L, R, c, m + 1, r, rson);
    	pushup(rt);
    }
    
    

    5.区间求和

    int query(int L, int R, int l, int r, int rt) {
    	if(L <= l && r <= R) return sum[rt];
    	pushdown(l, r, rt);
    	int m = (l + r) >> 1, ans = 0;
    	if(L <= m) ans += query(L, R, l, m, lson);
    	if(R > m) ans += query(L, R, m + 1, r, rson);
    	return ans;
    }
    

    代码

    下面上传高清无码无水印代码

    #include <bits/stdc++.h>
    #define N 100011
    #define lson rt << 1
    #define rson rt << 1 | 1
    #define int long long
    using namespace std;
    
    int sum[N << 2], lazy[N << 2], n, m;
    
    inline int read() {
    	char c = getchar();
    	int x = 0, f = 1;
    	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
    	return x * f;
    }
    
    inline void pushup(int rt) {
    	sum[rt] = sum[lson] + sum[rson];
    }
    
    void build(int l, int r, int rt) {
    	if(l == r) {
    		sum[rt] = read();
    		return;
    	}
    	int m = (l + r) >> 1;
    	build(l, m, lson);
    	build(m + 1, r, rson);
    	pushup(rt);
    }
    
    inline void pushdown(int l, int r, int rt) {
    	if(!lazy[rt]) return;
    	lazy[lson] += lazy[rt];
    	lazy[rson] += lazy[rt];
    	int m = (l + r) >> 1;
    	sum[lson] += (m - l + 1) * lazy[rt];
    	sum[rson] += (r - m) * lazy[rt];
    	lazy[rt] = 0;
    	return;
    }
    
    void update(int L, int R, int c, int l, int r, int rt) {
    	if(L <= l && r <= R) {
    		sum[rt] += c * (r - l + 1);
    		lazy[rt] += c;
    		return;
    	}
    	pushdown(l, r, rt);
    	int m = (l + r) >> 1;
    	if(L <= m) update(L, R, c, l, m, lson);
    	if(R > m) update(L, R, c, m + 1, r, rson);
    	pushup(rt);
    }
    
    int query(int L, int R, int l, int r, int rt) {
    	if(L <= l && r <= R) return sum[rt];
    	pushdown(l, r, rt);
    	int m = (l + r) >> 1, ans = 0;
    	if(L <= m) ans += query(L, R, l, m, lson);
    	if(R > m) ans += query(L, R, m + 1, r, rson);
    	return ans;
    }
    
    signed main() {
    	n = read(), m = read();
    	build(1, n, 1);
    	for(int i = 1; i <= m; i++) {
    		int opt = read(), x = read(), y = read();
    		if(opt == 1) {
    			int k = read();
    			update(x, y, k, 1, n, 1);
    		}
    		if(opt == 2) cout << query(x, y, 1, n, 1) << '
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    按照指定的字符串拆分字符串,split()方法。
    charAt()取出指定位置的字符 .length()得到一个字符串的长度 indexOf()查找一个指定的字符是否存在并返回其位置 trim()去掉字符串的左右空格 substring()字符串的截取 str.replace(" ", ""); 去掉所有空格,包括首尾、中间
    字符串与字符数组的多种转换方式。
    匿名对象。
    构造方法。
    递归的练习,1.统计文件夹大小 2.删除文件夹及文件夹下的文件
    jquery零散小饼干
    jQuery review
    git解决冲突
    url、href、src
  • 原文地址:https://www.cnblogs.com/loceaner/p/11122049.html
Copyright © 2011-2022 走看看