链接:https://www.nowcoder.com/acm/contest/135/I
来源:牛客网
题目描述
Apojacsleam喜欢数组。
他现在有一个n个元素的数组a,而他要对a[L]-a[R]进行M次操作:
操作一:将a[L]-a[R]内的元素都加上P
操作二:将a[L]-a[R]内的元素都减去P
最后询问a[l]-a[r]内的元素之和?
请认真看题干及输入描述。
输入描述:
输入共M+3行:
第一行两个数,n,M,意义如“题目描述”
第二行n个数,描述数组。
第3-M+2行,共M行,每行四个数,q,L,R,P,若q为1则表示执行操作2,否则为执行操作1
第4行,两个正整数l,r
输出描述:
一个正整数,为a[l]-a[r]内的元素之和
示例1
输入
10 5
1 2 3 4 5 6 7 8 9 10
1 1 5 5
1 2 3 6
0 2 5 5
0 2 5 8
1 4 9 6
2 7
输出
23
说明
题意:区间修改,区间询问的模版题
思路:模版题,但是不知道为何初始存的时候那里出错了,所以用了一个操作记录一下,输出即可
//
// main.cpp
// 区间
//
// Created by dhl on 2018/7/22.
// Copyright © 2018年 dhl. All rights reserved.
//
#include <iostream>
using namespace std;
const int maxn = 1e6 + 5;
#define ll long long
int n, m;
ll a[maxn], sum1[maxn], sum2[maxn];
void add(ll p, ll x){
for(ll i = p; i <= n; i += i & -i) {
sum1[i] += x;
sum2[i] += x * p;
}
}
void range_add(ll l, ll r, ll x){
add(l, x);
add(r + 1, -x);
}
ll ask(ll p){
ll res = 0;
for(ll i = p; i; i -= i & -i)
res += (p + 1) * sum1[i] - sum2[i];
return res;
}
ll range_ask(ll l, ll r){
return ask(r) - ask(l - 1);
}
int main(int argc, const char * argv[]) {
ios::sync_with_stdio(false);
cin >> n >> m;
a[0] = 0;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
sum1[i] = a[i] - a[i - 1];
sum2[i] = sum1[i] * i;
}
for (int i = 1; i <= n; i ++) {
a[i] -= range_ask(i, i);
}
for (int i = 1; i <= m; i ++) {
int q, l, r, p;
cin >> q >> l >> r >> p;
if (q == 1)
p *= -1;
range_add(l, r, p);
}
int l, r;
cin >> l >> r;
for (int i = 1; i <= n; i ++) {
a[i] += range_ask(i, i);
}
ll ans = 0;
for (int i = l; i <= r; i ++) {
ans += a[i];
}
cout << ans << endl;
return 0;
}
//10 5
//1 2 3 4 5 6 7 8 9 10
//1 1 5 5
//1 2 3 6
//0 2 5 5
//0 2 5 8
//1 4 9 6
//2 7
刚才看到学长写的,对于树状数组又有了新的认识
用sum来代表差分数组,对l-r的区间修改就是对sum[l]+=x,sum[r + 1]-=x,sum的前i项和就是a[i]的值(深刻体会)
为什么值改变sum[l]的值,a[i]也会跟着改变呢,应sum[l]改变,意味着a[i]与a[l-1]的差值多了x,而sum[l +1] - sum[r]的值都不变,就是a[l+1]-a[r]的值的差值不变(因为他们增加了相同的x),而sum[r+1]的值减小,就代表着a[r] 值变大而a[r+1]不变,所以差值就减小了。而计算的时候,sum[i]的前i项和,就相当与a[i]的变化量在与a[i]相加,就得到变化后的a[i]的值
//
// main.cpp
// 区间2
//
// Created by dhl on 2018/7/23.
// Copyright © 2018年 dhl. All rights reserved.
//
#include <iostream>
using namespace std;
const int maxn = 20;
int a[maxn], sum[maxn];
int main(int argc, const char * argv[]) {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++)
cin >> a[i];
for (int i = 1; i <= m; i ++) {
int q, l, r, w;
cin >> q >> l >> r >> w;
if (q!= 1)
sum[r + 1] -=w, sum[l] += w;//l-r区间的改变
else
sum[r + 1] += w, sum[l] -= w;
}
for (int i = 1; i <= n; i ++) {
sum[i] += sum[i - 1];//sum之和就是a[i]的变化量
a[i] += sum[i];//相加得到a[i]变化后的值
}
int l, r;
cin >> l >> r;
long long ans = 0;
for (int i = l; i <= r; i ++)
ans += a[i];
cout << ans << endl;
return 0;
}
这里的sum是表示的是a[i]的变化值,如果sum一开始就表示a的差分数组
//
// main.cpp
// 区间2
//
// Created by dhl on 2018/7/23.
// Copyright © 2018年 dhl. All rights reserved.
//
#include <iostream>
using namespace std;
const int maxn = 1e6 + 5;
int a[maxn], sum[maxn];
int main(int argc, const char * argv[]) {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
sum[i] = a[i] - a[i - 1];
}
for (int i = 1; i <= m; i ++) {
int q, l, r, w;
cin >> q >> l >> r >> w;
if (q!= 1)
sum[r + 1] -=w, sum[l] += w;//l-r区间的改变
else
sum[r + 1] += w, sum[l] -= w;
}
for (int i = 1; i <= n; i ++) {
a[i] = sum[i] += sum[i - 1];
}
int l, r;
cin >> l >> r;
long long ans = 0;
for (int i = l; i <= r; i ++)
ans += a[i];
cout << ans << endl;
return 0;
}