线段树—一个简单的整数问题

题目描述

你有N个整数,A1,A2,...,AN。 你需要处理两种操作。 一种操作是在给定间隔中为每个数字添加一些给定数字。 另一种是要求给定间隔中的数字总和。

输入

第一行包含两个数字N和Q.1≤N,Q≤100000。
第二行包含N个数字,A1,A2,...,AN的初始值。 -1000000000≤AI≤1000000000。
接下来的Q行中的每一行代表一个操作。
“C a b c”表示将C添加到Aa,Aa + 1,...,Ab中的每一个。 -10000≤c≤10000。
“Q a b”表示查询Aa,Aa + 1,...,Ab的总和。

输出

你需要回到Q个询问,每个询问一行。

样例输入

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

样例输出

4
55
9
15

提示

总和可能超过32位整数的范围。

#include <iostream>
#include <cmath>
using namespace std;
long long int a,b,c;
long long int ans=0;
struct node             //定义线段树 
{
	int l,r,f;          //代表这个节点所代表的区间的左右端点,懒标记 
	long long int w;    //这个节点的权值合它的子节点的权值和 
}tree[500000];          //结构体要开4倍空间
void down(int k)                    //懒标记下传 
{
	tree[k*2].f+=tree[k].f;         //更改子节点的懒标记的值 
	tree[k*2+1].f+=tree[k].f; 
	tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);      
	tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1); 
	tree[k].f=0;                    //懒标记重新定义为0,防止二次使用 
}
void build (int k,int ll,int rr)   //k为第几个节点,ll、rrwei区间的左右端点 
{
	tree[k].l=ll,tree[k].r=rr;     //把节点看做是一个区间 
	if (rr==ll)       //如果到叶子结点 
	{
		cin>>tree[k].w;
		return ;                   //如果是子节点,返回,不用往下继续 
	}
	int mid=(ll+rr)/2;
	build (k*2,ll,mid);            //先往左走 
	build (k*2+1,mid+1,rr);        //再往右走 
	tree[k].w=tree[k*2].w+tree[k*2+1].w;    //如果走到叶子结点,返回之后不用走这一步 
}
void add(int k)                      
{
	if (tree[k].l>=a&&tree[k].r<=b)  //如果要修改的区间中包括了这个节点所有的子节点 
	{
		tree[k].w+=(tree[k].r-tree[k].l+1)*c;   //改变节点代表的权值
		tree[k].f+=c;
		return ;                     //还有[a、l]、[r、b]没有修改,返回上一个节点,往另一边寻找 
	}                                //往后走是要修改的区间[a、b]包括在[l、r]中 
	if (tree[k].f) down(k);          //如果这个节点的子节点被修改过,懒标记下传 
	int mid=(tree[k].l+tree[k].r)/2;
	if (a<=mid) add(k*2);              //如果a在中点的左边,往左节点找 
	if (b>mid) add(2*k+1);             //如果b在重点的右边,往右节点找 
	tree[k].w=tree[k*2].w+tree[2*k+1].w;
}
void sum(int k)
{
	if (tree[k].l>=a&&tree[k].r<=b)
	{
		ans+=tree[k].w;
		return ;                      //因为w代表这个区间的和,不用再递归求和 
	}
	if (tree[k].f) down(k);
	int mid=(tree[k].l+tree[k].r)/2; 
	if (a<=mid) sum(2*k);
	if (b>mid) sum(2*k+1);
} 
int main ()
{
	int n,q;
	char s;
	cin>>n>>q; 
	build (1,1,n);         //建树 
	for (int i=1;i<=q;i++)
	{
		cin>>s;
		if (s=='C') 
		{
			cin>>a>>b>>c;
			add(1); 
		}
		if (s=='Q') 
		{
			ans=0;
			cin>>a>>b;
			sum(1);
			cout<<ans<<endl;
		}
	} 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/tiantianac/article/details/81208197