P3372 【模板】线段树 1 树状数组

题目

在这里插入图片描述

思路

第一眼:树状数组暴力,区间和直接用前缀和做
好,70分
看来需要用数学推亿推了
树状数组的区间查询:查分
c 1 = a 1 , c 2 = a 2 − a 1 , c 3 = a 3 − a 2 . . . c i = a i − a i − 1 c_1=a_1,c_2=a_2-a_1,c_3=a_3-a_2...c_i=a_i-a_{i-1} c1=a1,c2=a2a1,c3=a3a2...ci=aiai1
特别地, a 0 = 0 a_0=0 a0=0
如果用c表示出a来,那么可以发现
a i = ∑ j = 1 i c j a_i=\sum_{j=1}^ic_j ai=j=1icj
所以得出前缀和
s u m i = ∑ j = 1 i ∑ k = 1 k c k sum_i=\sum_{j=1}^i\sum_{k=1}^kc_k sumi=j=1ik=1kck
= ( c 1 ) + ( c 1 + c 2 ) + . . . + ( c 1 + c 2 + . . . + c i ) =(c_1)+(c_1+c_2)+...+(c_1+c_2+...+c_i) =(c1)+(c1+c2)+...+(c1+c2+...+ci)
= i ∗ c 1 + ( i − 1 ) ∗ c 2 + . . . + 1 ∗ c i =i*c_1+(i-1)*c_2+...+1*c_i =ic1+(i1)c2+...+1ci
= i ∗ ( c 1 + c 2 + . . . + c i ) − ( 0 ∗ c 1 + 1 ∗ c 2 + . . . ( i − 1 ) ∗ c i ) =i*(c_1+c_2+...+c_i)-(0*c_1+1*c_2+...(i-1)*c_i) =i(c1+c2+...+ci)(0c1+1c2+...(i1)ci)
= i ∗ ∑ j = 1 i − i ∗ ∑ j = 1 i ( j − 1 ) ∗ c j =i*\sum_{j=1}^i-i*\sum_{j=1}^i(j-1)*c_j =ij=1iij=1i(j1)cj
然后分别用T1,T2存这两项
理论存在,实践开始

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x)&(-(x))
int n,m;
struct BIT{
	static const int M=1e5+5;
	int c[M];
	void add(int x,int k) { while(x<=n) c[x]+=k,x+=lowbit(x); }
	int query(int x) { int sum=0;while(x>0) sum+=c[x],x-=lowbit(x);return sum; }
}T1,T2;
signed main()
{
	cin>>n>>m;
	int a,c=0;
	for(int i=1;i<=n;i++){
		cin>>a;
		c=a-c;
		T1.add(i,c),T2.add(i,(i-1)*c);
		c=a;
	}
	while(m--){
		int if_case;
		cin>>if_case;
		int x,y,k;
		switch (if_case){
			case 1:cin>>x>>y>>k;T1.add(x,k),T1.add(y+1,-k),T2.add(x,k*(x-1)),T2.add(y+1,-k*(y+1-1));break;
			case 2:cin>>x>>y;int sq=y*T1.query(y)-(x-1)*T1.query(x-1);int sh=T2.query(y)-T2.query(x-1);cout<<sq-sh<<endl;break;
		}
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值