线段树离散化求调
  • 板块灌水区
  • 楼主M_Jun
  • 当前回复3
  • 已保存回复3
  • 发布时间2024/12/7 17:25
  • 上次更新2024/12/7 20:28:01
查看原帖
线段树离散化求调
1098953
M_Jun楼主2024/12/7 17:25

总感觉没有听懂教练讲的啥意思,大脑一团乱麻,玄关求教

#include <algorithm> 
#include <iostream>

#define int long long
#define size sizes

using namespace std ;

const int N = 1e7 ;

int n ;
int m ;
int input[N] ;

int size ;
int num[N] ;

int way, l, r, x ;

struct Node_tree {
    int l, r ;
    int maxn, sum ;
    int lazy ;
} tree[4 * N + 5] ;

// 离散化配套的二分查找
int lower_b(int x[], int r, int k) {
	int l = 1 ;
	while(l <= r) {
		int mid = (l + r) >> 1 ;
		if(x[m] == k) return mid ;
		if(k < x[m]) r = mid - 1 ;
		else l = mid + 1 ;
	}
	
	return -1 ;
}

// 离散化 
void Discretization() {
	for(register int i = 1 ; i <= n ; i ++)
		num[i] = input[i] ;
	sort(num + 1, num + 1 + n) ;
	size = unique(num + 1, num + n + 1) - num ;
	/*也可以为: 
		size = 1 ;
		for(register int i = 1 ; i <= n ; i ++)
			if(sub[i] > sub[i - 1]) a[size ++] = a[i] ; 
	*/
	for(register int i = 1 ; i <= n ; i ++)
		input[i] = lower_bound(num + 1, num + n + 1, input[i]) - num ;
	/*也可以为:
		for(register int i = 1 ; i <= n ; i ++)
			a[i] = lower_bound(a + 1, size, sub[i]) ;
	*/
}

// 数据上传(更新父节点)
void push_up(int id) {
    tree[id].sum = tree[id * 2].sum + tree[id * 2 + 1].sum ;
    tree[id].maxn = max(tree[id * 2].maxn, tree[id * 2 + 1].maxn) ;
}

// 数据下传(传播懒标记)
void push_down(int id, int l, int r) {
    if (tree[id].lazy != 0) {  // 如果有懒标记
        int mid = (l + r) >> 1 ;
        // 更新左子树和右子树的lazy值
        tree[id * 2].lazy += tree[id].lazy ;
        tree[id * 2 + 1].lazy += tree[id].lazy ;
        
        // 更新左子树和右子树的sum和maxn
        tree[id * 2].sum += tree[id].lazy * (mid - l + 1) ;
        tree[id * 2 + 1].sum += tree[id].lazy * (r - mid) ;
        tree[id * 2].maxn += tree[id].lazy * (mid - l + 1) ;
        tree[id * 2 + 1].maxn += tree[id].lazy * (r - mid) ;

        // 清除懒标记
        tree[id].lazy = 0;
    }
}

// 建线段树
void build(int id, int l, int r) {
    tree[id].l = l; tree[id].r = r ;
    if (l == r) {  // 叶子结点的特判 
        tree[id].sum = num[l] ;
        tree[id].maxn = num[l] ;
    } else {
        int mid = (l + r) >> 1 ;
        build(id * 2, l, mid) ;  // 构建左子树
        build(id * 2 + 1, mid + 1, r) ;  // 构建右子树
        push_up(id) ;  // 更新当前节点的值
    }
}

// 区间修改
void change(int id, int l, int r, int x) {
	//当前到了编号为 id 的节点,要把 [l..r] 区间中的所有元素的值 +x
    if (l <= tree[id].l && r >= tree[id].r) {// 当前节点的区间完全包含在需要修改的区间中
        tree[id].sum += (tree[id].r - tree[id].l + 1) * x ;  // 更新sum
        tree[id].maxn += x ;  // 更新 maxn
        tree[id].lazy += x ;  // 记录懒标记
        return;
    }
    push_down(id, tree[id].l, tree[id].r) ;  // 先下传懒标记

    int mid = (tree[id].l + tree[id].r) >> 1 ;
    if (l <= mid) change(id * 2, l, r, x) ;  // 修改左子树
    if (r > mid) change(id * 2 + 1, l, r, x) ;  // 修改右子树
    push_up(id) ;  // 更新当前节点
}

// 区间查询
int query(int id, int l, int r) {
	//当前到了编号为 id 的节点,查询 [l..r] 的和
    if (l <= tree[id].l && r >= tree[id].r) return tree[id].sum ;// 当前节点的区间完全包含在查询的区间中
    push_down(id, tree[id].l, tree[id].r) ;  // 先下传懒标记 

    int mid = (tree[id].l + tree[id].r) >> 1 ;
    int res = 0;
    if (l <= mid) res += query(id * 2, l, r) ;  // 查询左子树
    if (r > mid) res += query(id * 2 + 1, l, r) ;  // 查询右子树
    
    return res;
}

signed main() {
    cin >> n >> m ;
    for (int i = 1 ; i <= n ; i ++) 
        cin >> input[i] ;
        
	Discretization() ;
    build(1, 1, n);  // 构建线段树

    for (int i = 1; i <= m; i++) {
        cin >> way >> l >> r;
        if (way == 1) {
            cin >> x ;
            change(1, l, r, x) ;  // 区间加值
        } else if (way == 2) 
            cout << query(1, l, r) << '\n' ;  // 查询区间和
    }

    return 0 ;
}
2024/12/7 17:25
加载中...