• 线段树模板


    线段树2020

    单点更新,区间查询,维护区间和

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6+10;
    int n,m,a[N];
    int sumv[N<<2];
    
    //合并 
    void pushup(int o){
    	sumv[o] = sumv[o<<1] + sumv[o<<1|1];
    }
    
    //建树 
    void build(int o,int l,int r){
    	if(l == r) { //到最后一行了 [1,1] [2,2] ... 
    		sumv[o] = a[l];
    		return;
    	}
    	int mid = (l+r)>>1; 
    	build(o<<1,l,mid);
    	build(o<<1|1,mid+1,r);
    	pushup(o);//向上合并 
    }
    
    //a[x] += y : change(1,1,n,x,y); 
    //单点修改  o为当前到达节点的编号 
    void change(int o,int l,int r,int pos,int v){
    	if(l == r){
    		sumv[o] += v;
    		return;
    	}	
    	int mid = (l+r)>>1;
    	if(pos <= mid) change(o<<1,l,mid,pos,v);//前半段区间
    	else change(o<<1|1,mid+1,r,pos,v); //后半段区间
    	pushup(o); //向上更新  有一些线段树维护了多个值,所以pushup不止一条 
    }
    
    //区间查询 
    int querysum(int o,int l,int r,int ql,int qr){
    	if(ql<=l && r<=qr) return sumv[o];//要查询的区间完全包含了[l,r] 
    	int ans = 0;
    	int mid = (l+r)>>1;
    	if(ql<=mid) ans += querysum(o<<1,l,mid,ql,qr);
    	if(qr>mid) ans += querysum(o<<1|1,mid+1,r,ql,qr);
    	return ans;
    }
    
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	build(1,1,n);
    	while(m--){
    		int opt;
    		cin>>opt;
    		if(opt == 1){
    			int x,y;
    			cin>>x>>y;
    			change(1,1,n,x,y);
    		}
    		if(opt == 2){
    			int l,r;
    			cin>>l>>r;
    			cout<<querysum(1,1,n,l,r)<<endl;
    		}
    	}
    }
    
    

    单点更新,区间查询,维护区间最小值

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6+10;
    int n,m,a[N];
    int minv[N<<2];
    
    //建树 
    void build(int o,int l,int r){
    	if(l == r) { //到最后一行了 [1,1] [2,2] ... 
    		minv[o] = a[l];
    		return;
    	}
    	int mid = (l+r)>>1; 
    	build(o<<1,l,mid);
    	build(o<<1|1,mid+1,r);
    	pushup(o);//向上合并 
    }
    
    void pushup(int o){
    	minv[o] = min(minv[o<<1],minv[o<<1|1]);
    }
    
    
    
    //a[x] += y : change(1,1,n,x,y); 
    //单点修改  o为当前到达节点的编号 
    void change(int o,int l,int r,int pos,int v){
    	if(l == r){
    		minv[o] += v;
    		return;
    	}	
    	int mid = (l+r)>>1;
    	if(pos <= mid) change(o<<1,l,mid,pos,v);//前半段区间
    	else change(o<<1|1,mid+1,r,pos,v); //后半段区间
    	pushup(o); //向上更新  有一些线段树维护了多个值,所以pushup不止一条 
    }
    
    //区间查询 
    int querymin(int o,int l,int r,int ql,int qr){
    	if(ql<=l && r<=qr) return minv[o];//要查询的区间完全包含了[l,r] 
    	int ans = 1e9+7; //为了求区间最小 初始要设置一个比较大的值 
    	int mid = (l+r)>>1;
    	if(ql<=mid) ans = min(ans,querymin(o<<1,l,mid,ql,qr));
    	if(qr>mid) ans = min(ans,querymin(o<<1|1,mid+1,r,ql,qr));
    	return ans;
    }
    
    
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	build(1,1,n);
    	while(m--){
    		int opt;
    		cin>>opt;
    		if(opt == 1){
    			int x,y;
    			cin>>x>>y;
    			change(1,1,n,x,y);
    		}
    		if(opt == 2){
    			int l,r;
    			cin>>l>>r;
    			cout<<querymin(1,1,n,l,r)<<endl;
    		}
    	}
    }
    

    区间修改,区间查询,标记下放

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6+10;
    int n,m,a[N];
    int sumv[N<<2],addv[N<<2];
    
    //合并 
    void pushup(int o){
    	sumv[o] = sumv[o<<1] + sumv[o<<1|1];
    }
    
    //建树 
    void build(int o,int l,int r){
    	if(l == r) { //到最后一行了 [1,1] [2,2] ... 
    		sumv[o] = a[l];
    		return;
    	}
    	int mid = (l+r)>>1; 
    	build(o<<1,l,mid);
    	build(o<<1|1,mid+1,r);
    	pushup(o);//向上合并 
    }
    
    void puttag(int o,int l,int r,int v){
    	addv[o] += v;
    	sumv[o] += (r-l+1)*v;
    }
    
    void pushdown(int o,int l,int r){
    	if(addv[o] == 0) return;
    	addv[o<<1] += addv[o];
    	addv[o<<1|1] += addv[o];
    	int mid = (l+r)>>1;
    	sumv[o<<1] += addv[o] * (mid-l+1);
    	sumv[o<<1|1] += addv[o] * (r-mid);
    	addv[o] = 0;
    } 
    
    void optadd(int o,int l,int r,int ql,int qr,int v){
    	if(ql<=l&&r<=qr){ //1.完全覆盖(l,r)这个子区间 就先更新好值,打上标记(为后面作标记准备)
    		puttag(o,l,r,v); //在puttag这里更新区间的值 打上标记 
    		return;
    	}
    	int mid = (l+r)>>1;
    	pushdown(o,l,r);//标记下放 因为接下来要更新子区间了
    	if(ql <= mid) optadd(o<<1,l,mid,ql,qr,v);
    	if(qr > mid) optadd(o<<1|1,mid+1,r,ql,qr,v);
    	pushup(o);
    }
    
    int querysum(int o,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr) return sumv[o];
    	int ans = 0;
    	int mid = (l+r)>>1;
    	pushdown(o,l,r);
    	if(ql<=mid) ans+=querysum(o<<1,l,mid,ql,qr);
    	if(qr>mid) ans+=querysum(o<<1|1,mid+1,r,ql,qr);
    	return ans;
    }
    
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	build(1,1,n);
    	while(m--){
    		int opt;
    		cin>>opt;
    		if(opt == 1){ //区间加 
    			int l,r,v;
    			cin>>l>>r>>v;
    			optadd(1,1,n,l,r,v);
    		}
    		if(opt == 2){
    			int l,r;
    			cin>>l>>r;
    			cout<<querysum(1,1,n,l,r)<<endl;
    		}
    	}
    }
    

    线段树2019

    单点更新区间查询,维护最小值

    #include <iostream>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int maxn = 110;
    int a[maxn];//原数组 
    int minv[4 * maxn];//维护最小值
    
    /*
    单点更新
    区间查询 
    */ 
    
    //维护 
    void pushup(int id) {
        minv[id] = min(minv[id << 1], minv[id << 1 | 1]);
    }
    
    //建树 
    void build(int id, int l, int r) {
        if (l == r) {
            minv[id] = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
        pushup(id);
    }
    
    //更新 
    void update(int id, int l, int r, int x, int v) {
        if (l == r) {
            minv[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);
        }
        pushup(id);
    }
    
    //查询 
    int query(int id,int l,int r,int x,int y){
        if(x <= l && r <= y){
            return minv[id];
        }
        int mid = (l + r) >> 1;
        int ans = inf;
        if( x <= mid){
            ans = min(ans,query(id << 1, l, mid, x,y));
        }
        if( y > mid){
            ans = min(ans,query( id<< 1 | 1,mid + 1,r,x,y));
        }
        return ans;
    }
    
    int main() {
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
        build(1, 1, n);
        int q;
        cin >> q;
        for (int i = 0; i < q; ++i) {
            int x, v;
            cin >> x >> v;
            update(1, 1, n, x, v);
        }
        int p;
    	cin >> p;
    	for (int i = 0; i < p; ++i) {
    		int l, r;
    		cin >> l >> r;
    		cout << query(1, 1, n, l, r) << endl;
    	}
        return 0;
    }
    

    区间更新,区间查询,维护赋值修改

    void up(int p)
    {
        if (!p) return;
        s[p] = s[p * 2] + s[p * 2 + 1];
    }
    
    void down(int p, int l, int r)
    {
        if (col[p])
        {
            int mid = (l + r) / 2;
            s[p * 2] = col[p] * (mid - l + 1);
            s[p * 2 + 1] = col[p] * (r - mid);
            col[p * 2] = col[p * 2 + 1] = col[p];
            col[p] = 0;
        }
    }
    
    void modify(int p, int l, int r, int x, int y, int c)
    {
        if (x <= l && r <= y)
        {
            s[p] = (r - l + 1) * c;  //仅修改该结点
            col[p] = c;  //增加标记,子结点待修改
            return;
        }
        down(p, l, r);  //下传lazy标记
          int mid = (l + r) / 2;
        if (x <= mid) modify(p * 2, l, mid, x, y, c);
        if (y > mid) modify(p * 2 + 1, mid + 1, r, x, y, c);
        up(p);
    }
    
  • 相关阅读:
    0302 随想
    1231递归下降语法分析程序设计
    《构建之法》1、2、3章读后感
    复利计算总结
    操作系统实验0
    学习进度条
    0302思考并回答一些问题
    评论
    c语言文法
    词法分析
  • 原文地址:https://www.cnblogs.com/fisherss/p/10920642.html
Copyright © 2020-2023  润新知