给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
2、“Q l r”,表示询问 数列中第 l~r 个数的和。
对于每个询问,输出一个整数表示答案。
输入格式
第一行两个整数N,M。
第二行N个整数A[i]。
接下来M行表示M条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
数据范围
1≤N,M≤1051≤N,M≤105,
|d|≤10000|d|≤10000,
|A[i]|≤1000000000|A[i]|≤1000000000
输入样例:
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
在区间修改,单点查询中,我们用树状数组维护差分数组b[i],差分数组中 i 的前缀和代表着原数组中a[i]在经过诸多指令后所改变的值。若查询 i 经过诸多指令后的值 = => 原数组 中a[i] + getsum(i)(getsum(i)表示 b[ ]中i的前缀和)
现在这个问题是区间修改,区间查询。我们还是引入差分数组b[ ] 。
那么原数组a [ ] 在经过若干指令后,a[1 ~ x]所增加的值应该是每个1~ x中每个点增加的值的和。
上式可以写成
所以在本题中,我们在增加一个差分数组并用树状数组维护 i * b[i]。在增加一个前缀和数组记录原数组的前缀和。
AC Code:
#include
using namespace std;
typedef long long LL;
const LL Size = 100010;
LL a[Size],n,m;
LL d1[Size],d2[Size] ;
LL sum[Size];
LL lowbit(LL x)
{
return x&(-x);
}
void add1(LL x,LL num)
{
for(;x<=n;x += lowbit(x)) d1[x] += num;
}
void add2(LL x,LL num)
{
for(;x <= n;x += lowbit(x)) d2[x] += num;
}
LL getsum1(LL x){
LL ans = 0;
for(;x > 0;x -= lowbit(x)) ans += d1[x];
return ans;
}
LL getsum2(LL x)
{
LL ans = 0;
for(;x > 0;x -= lowbit(x)) ans += d2[x];
return ans;
}
int main()
{
cin>>n>>m;
for(LL i = 1;i <= n;++i) cin>>a[i],sum[i] += (sum[i - 1] + a[i]);
while(m--)
{
char op[2];int l,r,d;
cin>>op>>l>>r;
if(op[0]=='C'){
cin>>d;
add1(l,d);
add1(r+1,-d);
add2(l,l*d);
add2(r+1,-(r+1)*d);
}
else {
LL ans = sum[r]+(r+1)*getsum1(r) - getsum2(r);//若干指令后 1~r的值
LL res = sum[l-1] + l*getsum1(l-1) - getsum2(l-1);//若干指令后1~l - 1的值
cout<
一般这种求和问题还是靠线段树啊,lazy标记。
AC Code:
#include
using namespace std;
typedef long long LL;
const LL N = 100050;
struct Tree
{
LL l,r;
LL sum,add;
#define l(id) tree[id].l
#define r(id) tree[id].r
#define sum(id) tree[id].sum
#define add(id) tree[id].add
} tree[N*4+1];
LL a[N],n,m;
void build(LL id,LL l,LL r)
{
l(id) = l,r(id) = r;
if(l == r)
{
sum(id) = a[l];
}
else
{
LL mid = l + r >>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
sum(id) = sum(id<<1) + sum(id<<1|1);
}
}
void push_down(LL id)
{
if(add(id))
{
sum(id<<1) += add(id)*(r(id<<1) - l(id<<1) +1);
sum(id<<1|1) += add(id)*(r(id<<1|1) - l(id<<1|1)+1);
add(id<<1) += add(id);
add(id<<1|1) += add(id);
add(id) = 0;
}
}
void updata(LL id,LL l,LL r,LL d)
{
if(l <= l(id) && r>=r(id))
{
sum(id) += (LL)d*(r(id) - l(id) +1);
add(id) += d;
return ;
}
push_down(id);
LL mid = l(id) + r(id) >>1;
if(r<= mid) updata(id<<1,l,r,d);
else if(l>mid) updata(id<<1|1,l,r,d);
else
{
updata(id<<1,l,mid,d);
updata(id<<1|1,mid+1,r,d);
}
sum(id) = sum(id<<1) + sum(id<<1|1);
}
LL query(LL id,LL l,LL r)
{
if(l <= l(id)&&r >= r(id)) return sum(id);
push_down(id);
LL mid =l(id) + r(id) >>1;
if(r<=mid) return query(id<<1,l,r);
else if(l>mid) return query(id<<1|1,l,r);
else return query(id<<1,l,mid) + query(id<<1|1,mid+1,r);
}
int main()
{
//freopen("1.in","r",stdin);
cin>>n>>m;
for(LL i = 1; i<=n; ++i) scanf("%lld",&a[i]);
build(1,1,n);
while(m--)
{
char op[2];
LL l,r,d;
scanf("%s%lld%lld",op,&l,&r);
if(op[0]=='C')
{
scanf("%lld",&d);
updata(1,l,r,d);
}
else printf("%lld\n",query(1,l,r));
}
}
AC Code:
//ECUST luoyongjun
#include
using namespace std;
const int MAXN = 1e5 + 10;
long long sum[MAXN << 2], add[MAXN << 2]; //4倍空间
void push_up(int rt){ //向上更新,通过当前结点rt把值递归但父结点
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void push_down(int rt, int m){ //更新rt的子结点
if(add[rt]){
add[rt << 1] += add[rt];
add[rt << 1 | 1] += add[rt];
sum[rt << 1] += (m - (m >> 1)) * add[rt];
sum[rt << 1 | 1] += (m >> 1) * add[rt];
add[rt] = 0; //取消本层标记
}
}
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
void build(int l, int r, int rt){ //用满二叉树建树
// add[rt] = 0;
if(l == r){ //叶子结点,赋值
scanf("%lld", &sum[rt]);
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
push_up(rt); //向上更新区间和
}
void update(int a, int b, long long c, int l, int r, int rt){//区间更新
if(a <= l && b >= r){
sum[rt] += (r - l + 1) * c;
add[rt] += c;
return;
}
push_down(rt, r - l + 1);//向下更新
int mid = (l + r) >> 1;
if(a <= mid) update(a, b, c, lson); //分成两半,继续深入
if(b > mid) update(a, b, c, rson);
push_up(rt);//向上更新
}
long long query(int a, int b, int l, int r, int rt){ //区间求和
if(a <= l && b >= r) return sum[rt]; //满足lazy,直接返回值
push_down(rt, r - l + 1); //向下更新
int mid = (l + r) >> 1;
long long ans = 0;
if(a <= mid) ans += query(a, b, lson);
if(b > mid) ans += query(a, b, rson);
return ans;
}
int main(void){
int n, m;
scanf("%d%d", &n, &m);
build(1, n, 1);
while(m--){
char str[2];
int a, b; long long c;
scanf("%s", str);
if(str[0] == 'C'){
scanf("%d%d%lld", &a, &b, &c);
update(a, b, c, 1, n, 1);
}else{
scanf("%d%d", &a, &b);
printf("%lld\n", query(a, b, 1, n, 1));
}
}
}