• 线段树


    简介

    注意事项

    开数组要开4倍大小,可以不用判断结束的边界条件。

    代码

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #define maxn 100000
    #define inf -1000000
    using namespace std;
    
    //maxv数组记录每一个区间内的最大值
    //sum数组记录区间和
    //add数组记录这个区间需要被加的数(lazy) 
    int a[maxn], sum[maxn << 2], add[maxn << 2];
    
    //ln左子树节点个数
    //rn右子树节点个数 
    void pushdown(int id, int ln, int rn){
    	if(add[id]){
    		add[id << 2] += add[id];
    		add[id << 2 | 1] = add[id];
    		sum[id << 2] += add[id] * ln;
    		sum[id << 2 | 1] += add[id] * rn;
    		add[id] = 0;
    	}
    }
    //建树 
    void build(int id, int l, int r){
    	if(l == r){
    		sum[id] = a[l];
    		add[id] = 0;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(id << 1, l, mid);
    	build(id << 1 | 1, mid + 1, r);
    	sum[id] = sum[id << 1] + sum[id << 1| 1];
    }
    
    //点更新 把 x 变为 v 
    void update(int id, int l, int r, int x, int v){
    	if(l == r){
    		sum[id] = v;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(x <= mid){
    		update(id << 1, l, mid, x, v);
    	}
    	else{
    		update(id << 1 | 1, mid + 1, r, x, v);
    	}
    	sum[id] = sum[id << 1] + sum[id << 1| 1];
    }
    //区间更新 x-_ry 所有节点 + C 
    void update(int id, int l, int r, int x, int y, int c){
    	if(x <= l && y >= r){
    		sum[id] += c * (r - l + 1);
    		add[id] += c;
    		return;
    	}
    	int mid = (r + l) >> 1;
    	pushdown(id, mid - l + 1, r - mid);
    	if(x <= mid){
    		update(id << 1, l, mid, x, y, c);
    	}
    	if(y > mid){
    		update(id << 1 | 1, mid + 1, r, x, y, c);
    	}
    	sum[id] = sum[id << 1] + sum[id << 1| 1];
    }
    //区间查询 x-y 
    int query(int id, int l, int r, int x, int y){
    	if(x <= l && y >= r){
    		return sum[id];
    	}
    	int mid = (l + r) >> 1;
    	pushdown(id, mid - l + 1, r - mid);
    	int ans = 0;
    	if(x <= mid){
    		ans += query(id << 1, l, mid, x, y);
    	}
    	if(y > mid){
    		ans += query(id << 1 | 1, mid + 1, r, x, y);
    	}
    	return ans;
    }
    
    int main(){
    	int n, m;
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++){
    		cin >> a[i];
    	}
    	build(1, 1, n);
    	for(int i = 0; i < m; i++){
    		int a, b, c, d;
    		cin >> a >> b >> c;
    		if(a == 1){
    			update(1, 1, n, b, c);
    		}
    		else if(a == 2){
    			cout<< query(1, 1, n, b, c) << endl;
    		}
    		else if(a == 3){
    			cin >> d;
    			update(1, 1, n, b, c, d);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    复权、前复权和后复权
    Android Fragment完全解析,关于碎片你所需知道的一切
    Android Volley完全解析(四),带你从源码的角度理解Volley
    Android Volley完全解析(三),定制自己的Request
    Android Volley完全解析(二),使用Volley加载网络图片
    Android Volley完全解析(一),初识Volley的基本用法
    利用HTML5开发Android笔记(下篇)
    利用HTML5开发Android笔记(中篇)
    利用HTML5开发Android笔记(上篇)
    Android经常使用开源组件汇总
  • 原文地址:https://www.cnblogs.com/woxiaosade/p/10870346.html
Copyright © 2020-2023  润新知