050.等差数列差分
等差数列
- 首项
s - 末项
e - 共差
d
等差数列差分
在区间[l,r]上加上一个等差数列
知道了区间长度,根据 e - s = d * (r - l)
对于s,e,d我们可以知二求三
对于原始数组a[]={0,0,0,0,0,0,0}
在[1,4]加上一个等差数列s=5,d=2,e=11
我们希望得到{0,5,7,9,11,0,0}
对结果求一次差分逆过程
a[i]-=a[i-1]
得到{0,5,2,2,2,-11,0}
再求一次差分逆过程
a[i]-=a[i-1]
得到{0,5,-3,0,0,-13,11}
我们发现中间的若干项都变成0了,我们只需要修改4个位置
0,0,0 , s , d-s , 0,0,0,0,0,0,0,0,0 , -d-e , e , 0,0,0,0
最后进行两次累加更新即可
void change(int l,int r,int s,int d,int e){
d[l]+=s;
d[l+1]+=d-s;
d[r+1]+=-d-e;
d[r+2]+=e;
}
void update(int n){
for(int _=0;_<2;_++){
for(int i=1;i<=n;++i){
a[i]+=a[i-1];
}
}
}
习题
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
ll a[N]={0};
void change(int l,int r,ll s,ll d,ll e){
a[l]+=s;
a[l+1]+=d-s;
a[r+1]+=-d-e;
a[r+2]+=e;
}
void update(int n){
for(int k=0;k<2;++k){
for(int i=1;i<n;++i){
a[i]+=a[i-1];
}
}
}
void solve(){
int n,m,l,r;
ll s,e,d;
cin>>n>>m;
while(m--){
cin>>l>>r>>s>>e;
d=(e-s)/(r-l);
change(l-1,r-1,s,d,e);
}
update(n);
ll ans1=0,ans2=-1;
for(int i=0;i<n;++i){
ans1^=a[i];
if(a[i]>ans2)ans2=a[i];
}
cout<<ans1<<' '<<ans2;
}
int main(void){
cin.tie(0)->sync_with_stdio(0);
int T=1;
//cin>>T;
while(T--)solve();
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
const int offset=300005;
//为了保证差分的正确性,超出边界的位置也要处理,整体添加一个偏移量
ll a[N];
int n,m,v,x;
void change(int l,int r,int s,int d,int e){
a[l]+=s;
a[l+1]+=d-s;
a[r+1]+=-d-e;
a[r+2]+=e;
}
void update(int n){
for(int _=0;_<2;++_){
for(int i=1;i<=n+offset;++i){
a[i]+=a[i-1];
}
}
}
void solve(){
cin>>m>>n;
while(m--){
cin>>v>>x;
x+=offset;
change(x-3*v+1,x-2*v,1,1,v);
change(x-2*v+1,x,v-1,-1,-v);
change(x+1,x+2*v,1-v,1,v);
change(x+2*v+1,x+3*v-1,v-1,-1,1);
}
update(n);
for(int i=1;i<=n;++i){
cout<<a[i+offset]<<' ';
}
}
int main(void){
cin.tie(0)->sync_with_stdio(0);
int T=1;
//cin>>T;
while(T--)solve();
}
I am the bone of my sword

浙公网安备 33010602011771号