1.单点修改,区间查询
题面:
给定数列a[1],a[2],…,a[n],你需要依次进行 q个操作,操作有两类:
1 i x:给定i,x,将a[i]加上x;
2 l r:给定l,r,求 ∑ri=la[i]的值(换言之,求a[l]+a[l+1]+⋯+a[r]的值)
Input
第一行包含2个正整数n,q,表示数列长度个数,保证a≤n,q≤106
第二行n个整数a[1],a[2],…,a[n],表示初始数列,保证|a[i]|≤106
接下来q行,每行一个操作,为下列两种之一:
1 i x:给定i,x,将a[i]加上x;
2 l r:给定l,r,求 ∑ri=1a[i]的值;
保证1≤l≤r≤n, |x|≤106
Output
对于每个 2 l r 操作输出一行,每行有一个整数,表示所求的结果。
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
typedef long long ll;
ll n,q,aa[1111111],c[1111111],a,b,d;
ll lowbit(ll x){
return x&(-x);
}
void change(ll i,ll k){
while(i<=n){
c[i]+=k;
i+=lowbit(i);
}
}
ll getsum(ll n){
ll ans=0;
while(n>0){
ans+=c[n];
n-=lowbit(n);
}
return ans;
}
int main(){
scanf("%lld%lld",&n,&q);
rep(i,1,n){
scanf("%lld",&aa[i]);
change(i,aa[i]);}
rep(i,1,q){
scanf("%lld%lld%lld",&a,&b,&d);
if(a==1){
aa[b]+=d;
change(b,d);}
if(a==2)
printf("%lld\n",getsum(d)-getsum(b-1));
}
return 0;
}
2.区间修改,单点查询
题面:
给定数列a[1],a[2],…,a[n] ,你需要依次进行 q 个操作,操作有两类:
1 l r x:给定 l,r,x,对于所有i∈[l,r],将 a[i] 加上 x(换言之,将 a[l],a[l+1],…,a[r] 分别加上 x);
2 i:给定 i ,求 a[i] 的值。
Input
第一行包含 2 个正整数 n,q,表示数列长度和询问个数。保证1≤n,q≤106 。
第二行 n 个整数 a[1],a[2],…,a[n],表示初始数列。保证|a[i]|≤106 。
接下来 q 行,每行一个操作,为以下两种之一:
1 l r x:对于所有 i∈[l,r],将a[i]加上x;
2 i:给定 i,求 a[i] 的值。
保证 1≤l≤r≤106, |x|≤106。
Output
对于每个 2 i 操作,输出一行,每行有一个整数,表示所求的结果。
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
typedef long long ll;
ll n,q,aa[1111111],c[1111111],a,b,d,e;
ll lowbit(ll x){
return x&(-x);
}
void change(ll i,ll k){
while(i<=n){
c[i]+=k;
i+=lowbit(i);
}
}
ll getsum(ll n){
ll ans=0;
while(n>0){
ans+=c[n];
n-=lowbit(n);
}
return ans;
}
void update(ll x, ll v) {
for (ll i = x; i <= n; i += lowbit(i))
c[i] += v;
}
ll query(ll x) {
ll sum = 0;
for (ll i = x; i >= 1; i -= lowbit(i)) sum += c[i];
return sum;
}
int main(){
scanf("%lld%lld",&n,&q);
rep(i,1,n){
scanf("%lld",&aa[i]);
change(i,aa[i]-aa[i-1]);}
rep(i,1,q){
scanf("%lld",&a);
if(a==1){
scanf("%lld%lld%lld",&b,&d,&e);{
update(b,e);
update(d+1,-e);
}
}
if(a==2){
scanf("%lld",&b);{
printf("%lld\n",query(b));
}
}
}
return 0;
}
3.区间修改,区间查询
给定数列 a[1],a[2],…,a[n],你需要依次进行q个操作,操作有两类:
1 l r x:给定l,r,x,对于所有的i∈[l,r],将a[i]加上x(换言之,将a[l],a[l+1],…,a[r] 分别加上x)
2 l r:给定l,r,求∑ri=la[i]的值(换言之,求a[l]+a[l+1]+…+a[r]的值)
Input
第一行包含2个正整数n,q,表示数列长度和询问个数。保证1≤n,q≤106;
第二行n个整数a[1],a[2],…,a[n],表示初始数列。保证|a[i]|≤106。
接下来q行,每行一个操作,为以下两种之一:
1 l r x:对于所有的i∈[l,r],将a[i]加上x;
2 l r:输出∑ri=la[i]的值;
Output
对于每个 2 l r 操作,输出一行,每行有一个整数,表示所求的结果。
代码:
/*aa原数组
sum1[]:维护aa[]的差分数组的 树状数组;
sum2[]:sum2[i]=(i-1)*sum1[i];
令ans[i]=n*sum1[i]-sum2[i]:ans[]为维护aa[]的前缀和数组的 树状数组;
具体推导过程 另查阅~
*/
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
typedef long long ll;
ll sum1[2222222],sum2[2222222],aa[2222222];
ll a,l,r,x,n,q;
ll lowbit(ll n){
return n&(-n);
}
ll change(ll i, ll k){
ll x=i;
while(i<=n){
sum1[i]+=k;
sum2[i]+=k*(x-1);
i+=lowbit(i);
}
}
ll getsum(ll n){
ll ans=0,x=n;
while(n>0){
ans+=x*sum1[n]-sum2[n];
n-=lowbit(n);
}
return ans;
}
int main(){
scanf("%lld%lld",&n,&q);
rep(i,1,n){
scanf("%lld",&aa[i]);
change(i,aa[i]-aa[i-1]);
}
while(q--){
scanf("%lld",&a);
if(a==1){
scanf("%lld%lld%lld",&l,&r,&x);
change(l,x);
change(r+1,-x);
}
if(a==2){
scanf("%lld%lld",&l,&r);
printf("%lld\n",getsum(r)-getsum(l-1));
}
}
return 0;
}