先开始刷洛谷的差分算法,再继续开始2022年第2题
[[差分(difference)]]
### Day9: 1.# P2367 语文成绩 2.# P3397 地毯 3.202203-2
#### 1.# P2367 语文成绩(一维差分)
(1)题目就是要给原数组多段区间高效地加上一个常数,即利用差分算法
(2)代码(100):
```
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
int n,p;
cin>>n>>p;
vector<int> va(n+1,0);
vector<int> vd(n+1,0);
for(int i=1;i<=n;i++){
cin>>va[i];
}
for(int i=1;i<=n;i++){
vd[i]=va[i]-va[i-1];
}
int x,y,z;
while(p--){
cin>>x>>y>>z;
vd[x]+=z;
if(y+1<=n){
vd[y+1]-=z;
}
}
for(int i=1;i<=n;i++){
va[i]=va[i-1]+vd[i];
}
int min=numeric_limits<int>::max();
for(int i=1;i<=n;i++){
if(va[i]<min){
min=va[i];
}
}
cout<<min;
return 0;
}
```
#### 2.# P3397 地毯(二维差分)
(1)一开始写越界了,因为二维差分改变子矩阵的值涉及x2+1,y2+1,所以说差分数组D要比原数组行和列都至少大1
(2)代码(100):
```
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
vector<vector<int>> va(n+1,vector<int>(n+1,0));
vector<vector<int>> vd(n+2,vector<int>(n+2,0));//注意两个n+2
int x1,y1,x2,y2;
while(m--){
cin>>x1>>y1>>x2>>y2;
vd[x1][y1]++;
vd[x1][y2+1]--;
vd[x2+1][y1]--;
vd[x2+1][y2+1]++;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
va[i][j]=va[i-1][j]+va[i][j-1]-va[i-1][j-1]+vd[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<va[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
```
#### 3.202203-2:出行计划(差分)
(1)题目不等式写出来了,感觉是用差分和前缀和优化,但是没想出来究竟是哪个数组用前缀和,哪些区间差分加常数。
学习:
由题意可以列出:q+k≤t≤q+k+c−1
则q的范围是:t+1−k−c≤q≤t−k(因为q是查询,转化为q的范围,然后判断q)
题目给了n组(ti,ci),相应的就有n个区间[t+1−k−c,t−k]
即求对于每个q,要计算落在这n个区间内的哪几个区间中?(**区间判断**)
**等价于**:
我们可以想象一个数轴,数轴上的每个点处的数是0,**只要被一个区间覆盖,覆盖到的地方就全部+1**,这样处理这n个区间,我们就得到了这n个区间在数轴上的叠加覆盖,数轴上的数是几,那它就在几个区间内。
**即让区间[ti+1−k−ci,ti−k]内的数全部+1呢**(**差分**)
**优化核心**:把原先不等式比较转换为了数组元素查询获取次数
(2)满分代码:
```
#include <bits/stdc++.h>
using namespace std;
const int N=200010;
int main(){
ios::sync_with_stdio(false);
int n,m,k;
cin>>n>>m>>k;
int t,c;
vector<int> va(N,0);
vector<int> vd(N,0);
for(int i=1;i<=n;i++){
cin>>t>>c;
int x=t+1-k-c;
int y=t-k;
//题目q的范围引发的边界情况的讨论不能少
if(y<=0){
continue;
}
//数组的边界
x=max(1,x);
//for循环里面只改变差分数组
vd[x]++;
vd[y+1]--;
}
//只要构建前缀和数组一次即可
for(int i=1;i<=N;i++){
va[i]=va[i-1]+vd[i];
}
int q;
while(m--){
cin>>q;
cout<<va[q]<<endl;
}
return 0;
}
```