codevs-1082 线段树练习(其实我用的是树状数组)(区间修改,区间查询)

题目链接:http://codevs.cn/problem/1082/

题目描述 Description

给你N个数,有两种操作:


1:给区间[a,b]的所有数增加X


2:询问区间[a,b]的数的和。

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,

再接下来一个正整数Q,每行表示操作的个数,

如果第一个数是1,后接3个正整数,

扫描二维码关注公众号,回复: 2404605 查看本文章

表示在区间[a,b]内每个数增加X,如果是2,

表示操作2询问区间[a,b]的和是多少。

pascal选手请不要使用readln读入

输出描述 Output Description

对于每个询问输出一行一个答案

样例输入 Sample Input

3

1

2

3

2

1 2 3 2

2 2 3

样例输出 Sample Output

9

数据范围及提示 Data Size & Hint

数据范围

1<=n<=200000

1<=q<=200000

树状数组模板,区间修改,区间查询。

区间修改-区间查询的原理:

区间修改,区间查询:
引入一个函数:sigma(a,i)表示a数组的前i项和
引入一个差分数组,c[i]=a[i]-a[i-1];
因此:a[i]=sigma(c,i);
修改r~l的值:
c[l]=c[l]+x,c[r+1]=c[r+1]+(-x);即可

sum(1,k)表示区间1-k的和。
则sum(1,k)=c1(1)+( c1(1)+c1(2) )+( c1(1)+c1(2)+c1(3) )+
...+(c1(1)+c1(2)+c1(3)+...+c1(k)).
打开多项式,合并: 
sum(1,k)=k*( c1(1)+c1(2)+...+c1(k) )-( 0*c1(1)+1*c1(2)+2*c1(3)+...+(k-1)*c1(k) )。
因此分成两个数组,建立两个树状数组, 
分别为:
tree1 = k*( c1(1)+c1(2)+...+c1(k) )  前缀和 
tree1[]=c1(1),c1(2),c1(3), ... ,c1(k);
/*-------*/
tree2 =  ( 0*c1(1)+1*c1(2)+2*c1(3)+...+(k-1)*c1(k) )  i的前缀和 
tree2[]=c1(1)*0,c1(2)*1,c1(3)*2, ... ,(k-1)*c1(k);
用第一个减去第二个就是区间查询的结果了 

知道原理直接套用模板就行了:

ac:

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
//#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
#define INF 0x3f3f3f3f  
#define mod 1000000007
#define clean(a,b) memset(a,b,sizeof(a))// 水印 


ll tree1[200100],tree2[200100];
ll sum[200100];
int n,q;
/*--------模板-----------*/
int lowbit(int i)
{
	return i&(-i);
}

void updata(ll i,ll x,ll* tree)
{
	while(i<=n)
	{
		tree[i]=tree[i]+x;
		i=i+lowbit(i);
	}
}

ll Query(ll i,ll *tree)
{
	ll res=0;
	while(i>0)
	{
		res=res+tree[i];
		i=i-lowbit(i);
	}
	return res;
}
/*------------模板---------------*/
int main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		cin>>sum[i];
		sum[i]=sum[i]+sum[i-1];
	}
	cin>>q;
	for(int i=1;i<=q;++i)
	{
		int oper;
		cin>>oper;
		if(oper==1)
		{
			int a,b,x;
			cin>>a>>b>>x;
			updata(a,x,tree1);//增加的数组
			updata(b+1,-x,tree1);
			
			updata(a,x*a,tree2);//减少的数组
			updata(b+1,-(b+1)*x,tree2);
		}
		else
		{
			
//			sum[r]-sum[l-1];
//			(r+1)*Query(r,tree1)-l*Query(l-1,tree1);
//			-(Query(r,tree2)-Query(l-1,tree2));
			
			int a,b;
			cin>>a>>b;
			ll res=sum[b]-sum[a-1];
			res=res+(b+1)*Query(b,tree1)-a*Query(a-1,tree1);
			res=res-(Query(b,tree2)-Query(a-1,tree2));
			cout<<res<<endl;
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/81178470