P3368 【模板】树状数组 2
这道题目是差分数组与树状数组的结合,这题每次改变并且查询的是a数组,但是如果直接改变a数组又难免会出现每次都要重新进行前缀和等一系列操作,所以要思考如何将对段的修改变成对单个点的修改和查询,这就可以想到差分了。
例如原始数组是a,再新建一个数组b,使b[i] = a[i] - a[i - 1],如此一来就可以令a[i] = b[1] + b[2] + b[3] +........+ b[i],如此一来,假如要使a数组[l , r]区间内的元素急加上cnt,就只需要让b[l] += cnt,b[r + 1] -= cnt,如此一来就只需要修改单个点即可完成对a的改变,出现对单个点的修改与维护以及前缀和就会想到树状数组。
树状数组的add函数与query函数与树状数组1中的别无二致,这里就主要看一下主函数的变化。
ll last = 0;
for(int i = 1 ; i <= n ; i++)
{
int num;
cin>>num;
add(i , num - last);
last = num;
}
这里是读入a数组生成b数组。
while(m--)
{
int flag;
cin>>flag;
if(flag == 1)
{
int x,y,k;
cin>>x>>y>>k;
add(x , k);
add(y + 1 ,-k);
}else
{
int x;
cin>>x;
cout<<query(x)<<"\n";
}
}
这里的1操作是对a数组在区间[x , y]之间加上k,和正常的差分一样的思路,2操作则是输出第x个数的值,这里的query就是实现了a[i] = b[1] + b[2] + b[3] +........+ b[i]的操作,从顶层往下加即可。
最后是AC代码:
//#pragma GCC optimize(1)
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Os")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("Og")
//#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair <ll , ll> pii;
typedef priority_queue <ll ,vector<ll> ,greater<ll> > xiao;
typedef priority_queue <ll ,vector<ll> ,less<ll> > da;
const int N=5e5 + 10,M = 0x3f3f3f3f;
const ull P = 131;
int n,m;
int c[N];
ll lowbit(int x)
{
return x&(-x);
}
void add(int u,int cnt)
{
for(int i = u ; i <= n ; i += lowbit(i))
{
c[i] += cnt;
}
}
int query(int k)
{
int ans = 0;
for(int i = k ; i >= 1 ; i -= lowbit(i))
{
ans += c[i];
}
return ans;
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0),cout.tie(0);
cin>>n>>m;
ll last = 0;
for(int i = 1 ; i <= n ; i++)
{
int num;
cin>>num;
add(i , num - last);
last = num;
}
while(m--)
{
int flag;
cin>>flag;
if(flag == 1)
{
int x,y,k;
cin>>x>>y>>k;
add(x , k);
add(y + 1 ,-k);
}else
{
int x;
cin>>x;
cout<<query(x)<<"\n";
}
}
}