线段树&树状数组

#include <bits/stdc++.h>
#define lson l,m,k*2 
#define rson m+1,r,k*2+1 //左右儿子在函数里面用
#define int long long
using namespace std;
const int N=5000005;
int t[N],a[N],n,m,lazy[N];
void plusa(int l,int r,int k,int x) //当一个节点 k 所代表的区间 [l, r] 完全包含在待修改的区间(也就是父节点被lazy标记的区间)内时,我们需要更新这个节点的信息,但不需要立即更新它的所有子节点。
{
	lazy[k]+=x; //节点 k 所代表的整个区间,还需要再加 x
	t[k]+=(r-l+1)*x; //这个区间里面的所有元素都要加x,t[k]是左右儿子的和,所以t[k]自己要先把自己处理了
}
void pushup(int k) //凡是对左右儿子操作过的都要pushup更新
{
	t[k]=t[k*2]+t[k*2+1];
}
void pushdown(int l,int r,int k) //如果lazy有标记,那么要给左右儿子标记上去
{
	if(lazy[k])
	{
		int m=(l+r)/2;
		plusa(lson,lazy[k]);
		plusa(rson,lazy[k]);
		lazy[k]=0;
	}
}
void build(int l,int r,int k) //建一棵树
{
	if(l==r)
		t[k]=a[l];
	else
	{
		int m=(l+r)/2;
		build(lson);
		build(rson);
		pushup(k);
	}
}
void add(int L,int R,int x,int l,int r,int k) //区间修改
{
	if(l>=L&&R>=r)
	{
		plusa(l,r,k,x);
		return;
	}
	else
	{
		int m=(l+r)/2;
		pushdown(l,r,k);
		if(L<=m)
			add(L,R,x,lson);
		if(R>m)
			add(L,R,x,rson);
		pushup(k);
	}
}
int query(int L,int R,int l,int r,int k)
{
	if(L<=l&&r<=R)
		return t[k];
	int sum=0;
	int m=(l+r)/2;
	pushdown(l,r,k);
	if(L<=m)
		sum+=query(L,R,lson);
	if(R>m)
		sum+=query(L,R,rson);
	return sum;
} 
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(nullptr);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	build(1,n,1);
	while(m--)
	{
		int op,x,y;
		cin>>op>>x>>y;
		if(op==1)
		{
			int k;
			cin>>k;
			add(x,y,k,1,n,1);
		}
		else
			cout<<query(x,y,1,n,1)<<"\n";
	 } 
	return 0;
}
int n,m,a[500005],c[500005];
int lowbit(int x)
{
	return x&(-x);
}
void add(int i,int x)
{
	while(i<=n)
	{
		c[i]+=x;
		i+=lowbit(i);
	}
}
int query(int x)
{
	int s=0;
	while(x)
	{
		s+=c[x];
		x-=lowbit(x);
	}
	return s;
}
posted @ 2025-08-26 22:33  wtnbl  阅读(9)  评论(0)    收藏  举报