差分
797. 差分
题目链接
模板题:根据原数组构造差分数组,原数组为差分数组的前缀和数组
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int l, r, c;
int n, m;
void insert(int l, int r, int c){
b[l] += c;
b[r + 1] -= c;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++){
int x;
scanf("%d", &x);
insert(i, i, x);
}
while(m --){
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
for(int i = 1; i <= n; i ++) a[i] = a[i - 1] + b[i];
for(int i = 1; i <= n; i ++) printf("%d ", a[i]);
return 0;
}
增减序列
题目链接
-
差分序列的含义:
\(b[i] =\left\{\begin{matrix}a[i],i = 1\\a[i] - a[i - 1],i \geq 2 \end{matrix}\right.\) -
原序列与差分序列的对应关系:
| a[0] | a[1] | a[2] | ... | a[n] | 0 |
|---|---|---|---|---|---|
| 0 | a[1] - a[0] | a[2] - a[1] | ... | a[n] - a[n - 1] | 0 |
完整的差分数组有n + 1项,b[0]和b[n + 1]都为0,通过差分数组可以对原数组的任意一段同时加上或减去某个值。
- 具体规则如下:

Ac代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a[N], b[N];
int n;
void insert(int l, int r, ll c){
b[l] += c;
b[r + 1] -= c;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++){
ll x;
scanf("%lld", &x);
insert(i, i, x);
}
//for(int i = 1; i <= n; i ++) printf("%d ", b[i]);
ll sum1 = 0, sum2 = 0;
for(int i = 2; i <= n; i ++)
if(b[i] < 0) sum1 += b[i];
else sum2 += b[i];
printf("%lld\n", abs(sum1 + sum2) + min(-sum1, sum2));
printf("%lld\n", abs(sum1 + sum2) + 1);
return 0;
}
101.最高的牛
题目链接 https://www.acwing.com/problem/content/description/103/
解析
- 假设所有牛都是最大身高,如果(l, r)之间的牛可以看见,则insert(l + 1, r - 1, -1)
- 有两个坑点,一个是(l, r)的大小关系记得swap,另一个是对于可见关系描述可能重复,要先加入集合去重
Ac代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
typedef pair<int, int> PII;
const int N = 1e4 + 10;
#define x first
#define y second
int n, p, h, m;
int a[N], b[N];
set<PII> ss;
void insert(int l, int r, int c){
b[l] += c;
b[r + 1] -= c;
}
int main()
{
scanf("%d%d%d%d", &n, &p, &h, &m);
for(int i = 1; i <= n; i ++) insert(i, i, h);
while(m --){
int l, r;
scanf("%d%d", &l, &r);
if(l > r) swap(l, r);
ss.insert({l, r});
}
for(auto i : ss){
insert(i.x + 1, i.y - 1, -1);
}
for(int i = 1; i <= n; i ++) a[i] = a[i - 1] + b[i];
for(int i = 1; i <= n; i ++) printf("%d\n", a[i]);
return 0;
}
4007. 非零段划分
题目链接
https://www.acwing.com/problem/content/4010/
解析

Ac代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e5 + 10;
const int M = 1e4 + 10;
int a[N];
int b[N];
int n;
void insert(int l, int r, int c){
b[l] += c;
b[r + 1] -= c;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++){
if(a[i] > a[i - 1]) insert(a[i - 1], a[i] - 1, 1);
}
int ans = 0, res = 0;
for(int i = 0; i <= M; i ++){
ans += b[i];
res = max(ans, res);
}
printf("%d\n", res);
return 0;
}
2014. 岛
题目链接
https://www.acwing.com/problem/content/2016/
解析
与非零段划分方法相同,唯一区别在于使用map进行离散化,得到差分的map,注意map的遍历方法,可以用map是因为map默认按照第一维排序。
Ac代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
map<ll, ll> mp;
int n;
ll a[N];
void insert(int l, int r, int c){
mp[l] += c;
mp[r + 1] -= c;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
for(int i = 1; i <= n; i ++){
if(a[i] > a[i - 1]){
insert(a[i - 1], a[i] - 1, 1);
}
}
ll ans = 0, res = 0;
for(auto t : mp){
ans += t.second;
res = max(ans, res);
}
printf("%lld\n", res);
return 0;
}
1952 金发姑娘和N头牛
题目链接
https://www.acwing.com/problem/content/1954/
解析
与岛、非零段划分相同,都是算序列中每一个元素对于答案的贡献,最终形成一个横坐标为温度t的数组,然后遍历取最大值即可。本题和岛都需要用map离散化,目的在于按从小到大的顺序枚举温度t,算出最大的产值。
Ac代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
int n, x, y, z;
ll mmin, mmax;
map<ll, ll> mp;
void insert(ll l, ll r, ll c){
mp[l] += c;
mp[r + 1] -= c;
}
int main()
{
scanf("%d%d%d%d", &n, &x, &y, &z);
for(int i = 1; i <= n; i ++){
scanf("%lld%lld", &mmin, &mmax);
insert(0, mmin - 1, x);
insert(mmin, mmax, y);
insert(mmax + 1, 1e9, z);
}
ll ans = 0, res = 0;
for(auto i : mp){
ans += i.second;
res = max(ans, res);
}
printf("%lld\n", res);
return 0;
}
1715. 桶列表
题目链接
https://www.acwing.com/problem/content/1717/
解析
差分,时间作为横轴
Ac代码
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int a[N], s[N];
int n;
void insert(int l, int r, int c)
{
a[l] += c;
a[r + 1] -= c;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
insert(x, y, z);
}
int ans = 0;
for(int i = 1; i <= N; i ++){ //范围容易写错,不是1~n
s[i] = s[i - 1] + a[i];
ans = max(ans, s[i]);
}
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号