关于线段树的详细信息参考以下文章:

[文章链接] (https://blog.csdn.net/weixin_45697774/article/details/104274713?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164913869216780271988328%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164913869216780271988328&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-104274713.142^v5^pc_search_result_control_group,157^v4^control&utm_term=%E7%BA%BF%E6%AE%B5%E6%A0%91&spm=1018.2226.3001.4187)

本文不介绍线段树的详细信息,只给出线段树的部分模板:

1.区间查询,单点修改

[题目链接:] (https://www.luogu.com.cn/problem/P3374)

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+7;
typedef long long ll;
ll arr[500010],ans;
struct node
{
	int l,r;   //用于表示该节点包含的赋予范围,范围为[l~r];
	ll sum=0;   //用于存储该节点所含区域内所有数的和;
};
node tree[500010*4];   //存储线段树;
void build(int p,int l,int r)    //递归构建线段树;
{
	tree[p].l=l;tree[p].r=r;
	if(l==r){      //找到叶子节点,叶子节点存储数组arr内对应的值;
		tree[p].sum=arr[l];
		return ;
	}
	int mid=(l+r)/2;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;  //由二叉树的性质可知右孩子的下标是父节点的两倍,左孩子的下标是父节点的两倍加1;
	return ;
}
void add(int p,int x,int k)    //单点修改
{
	if(tree[p].l==tree[p].r){
		tree[p].sum+=k;       //递归查找需要修改的叶子节点,更新数值;
		return ;
	}
	int mid=tree[p].l+tree[p].r>>1;
	if(x<=mid) add(p<<1,x,k);   //如果目标节点在区间左侧,则进入该节点的左孩子,反之进入右孩子中
	else add(p<<1|1,x,k);
	tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;   //反向更新包含该节点的所有区间的数值总和
}
ll search(int p, int l,int r)   //区间查询
{
	if(tree[p].l>=l&&tree[p].r<=r) return tree[p].sum;  //如果这个区间被完全包括在目标区间里面,直接返回这个区间的值
	if(tree[p].l>r||tree[p].r<l) return 0; //如果这个区间和目标区间毫不相干,返回0
	int mid=tree[p].l+tree[p].r>>1;
	ll s=0;
	if(l<=mid) s+=search(p<<1,l,r); //如果这个区间的左儿子和目标区间又交集,那么搜索左儿子
	if(r>mid) s+=search(p<<1|1,l,r); //如果这个区间的右儿子和目标区间又交集,那么搜索右儿子
	return s;
}
int main() {
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>arr[i];
	build(1,1,n);
	int f;
	while(m--){
		cin>>f;
		int a,b;
		cin>>a>>b;
		if(f==1) add(1,a,b);
		else {
			ans=search(1,a,b);
			cout<<ans<<endl; 
		}
	}
	return 0;
}

2.区间修改,单点查询

[题目链接] (https://www.luogu.com.cn/problem/P3368)

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+7;
typedef long long ll;
ll arr[500010],ans;
struct node
{
	int l,r;
	ll num=0;
};
node tree[500010*4];
void build(int p,int l,int r)   //构建线段树,注意与上个模板的区别;
{
	tree[p].l=l;tree[p].r=r;
	if(l==r){
		tree[p].num=arr[l];
		return ;
	}
	int mid=(l+r)/2;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	return ;
}
void add(int p,int l,int r,int k)  //区间修改,注意修改的实现;
{
	if(tree[p].l>=l&&tree[p].r<=r){
		tree[p].num+=k;
		return ;
	}
	int mid=(tree[p].l+tree[p].r)/2;
	if(l<=mid) add(p<<1,l,r,k);
	if(r>mid) add(p<<1|1,l,r,k);
}
void query(int p, int x)  //单点查询
{
	ans+=tree[p].num;
	if(tree[p].l==tree[p].r) return ;
	int mid=(tree[p].l+tree[p].r)/2;
	if(x<=mid) query(p<<1,x);
	else query(p<<1|1,x);
}
int main() {
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>arr[i];
	build(1,1,n);
	int f;
	while(m--){
		cin>>f;
		if(f==1){
			int x,y,k;
			cin>>x>>y>>k;
			add(1,x,y,k);
		}
		else {
			int x;
			cin>>x;
			ans=0;
			query(1,x);
			cout<<ans<<endl;
		}
	}
	return 0;
}

3.区间修改,区间查询(修改仅适用于加减)

[题目链接] (https://www.luogu.com.cn/problem/P3372)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
const int inf=0x3f3f3f;
const int MAX=1000010;

struct node{
    int l,r;
    ll sum;
    int k;
};
node arr[MAX*2];
int pre[MAX];
void init(int i,int a,int b){
    int mid=(a+b)/2;
    arr[i].l=a;arr[i].r=b;arr[i].k=0;
    if(a==b) {
        arr[i].sum=pre[a];
        return ;
    }
    init(i*2,a,mid);
    init(i*2+1,mid+1,b);
    arr[i].sum=arr[i*2].sum+arr[i*2+1].sum;
}
void push_down(int i){
    if(arr[i].k!=0){
        arr[i*2].k+=arr[i].k;
        arr[i*2+1].k+=arr[i].k;
        int mid=(arr[i].l+arr[i].r)/2;
        arr[i*2].sum+=(mid-arr[i].l+1)*arr[i].k;
        arr[i*2+1].sum+=(arr[i].r-mid)*arr[i].k;
        arr[i].k=0;
    }
}
void fix(int i,int a,int b,int c){
    if(arr[i].l>=a&&arr[i].r<=b) {
        arr[i].sum+=(arr[i].r-arr[i].l+1)*c;
        arr[i].k+=c;
        return ;
    }
    push_down(i);
    int mid=(arr[i].l+arr[i].r)/2;
    if(mid>=a) fix(i*2,a,b,c);
    if(mid<b) fix(i*2+1,a,b,c);
    arr[i].sum=arr[i*2].sum+arr[i*2+1].sum;
}
ll seek(int i,int a,int b){
    if(arr[i].l>=a&&arr[i].r<=b) return arr[i].sum;
    push_down(i);
    int mid=(arr[i].l+arr[i].r)/2;
    if(mid>=b) return seek(i*2,a,b);
    else if(mid<a)  return seek(i*2+1,a,b);
    else return seek(i*2,a,mid)+seek(i*2+1,mid+1,b);
}
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>pre[i];
    init(1,1,n);
    while(m--){
        int f,a,b,c;
        cin>>f;
        if(f==1){
            cin>>a>>b>>c;
            fix(1,a,b,c);
        }
        else{
            cin>>a>>b;
            ll ans=seek(1,a,b);
            cout<<ans<<endl;
        }
    }
    return 0;
}