0
点赞
收藏
分享

微信扫一扫

浅谈差分和差分数组

代码敲到深夜 2022-04-16 阅读 76
c++

浅谈差分和差分数组

洛谷链接 acwing链接

定义:

差分,又名差分函数或差分运算,差分的结果反映了离散量之间的一种变化,是研究离散数学的一种工具,常用函数差近似导数。百度百科

差分数组反应的是后面一个数和前面一个数的大小关系。我们定义 c h a i cha_i chai a i a_i ai 的差分数组,表示 cha[i]=a[i]-a[i-1]主要用于 c h a i cha_i chai 是定值,快速求出 a j a_j aj 的时候

差分则主要用于动态的区间修改和单点询问,见下。

差分性质:

  • 如果将 l l l r r r 的范围内的数加上 k k k,反应在数组上就是 c h a l + k cha_l +k chal+k c h a r + 1 − k cha_{r+1}-k char+1k,因为区间修改时范围内的数的相对大小关系,是不会发生变化的。这时 a i a_i ai 的值等于 ( ∑ i = 1 i c h a i ) + a i (\sum_{i=1}^i cha_i)+a_i (i=1ichai)+ai

由此我们可以发现差分可以用于区间修改,单点询问的问题。

差分数组性质

  • c h a 1 cha_1 cha1 的值可以是任意实数。
  • a i a_i ai 的值等于 ( ∑ i = 1 i c h a i ) + a 1 (\sum_{i=1}^i cha_i)+a_1 (i=1ichai)+a1。(适用于 c h a i cha_i chai 为定值)

差分例题

典型例题一:

P2367 语文成绩

#include<bits/stdc++.h>
using namespace std;
int a[5000001];
int f[5000001];
int ans=100000;
int main(){
    int n,p;
    cin>>n>>p;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    while(p--){
        int x,y,z;
        cin>>x>>y>>z;
        f[x]+=z;
        f[y+1]-=z;
    }
    for(int i=1;i<=n;i++){
        f[i]+=f[i-1];
        a[i]+=f[i];
        ans=min(ans,a[i]);
    }
	cout<<ans<<endl; 
}

例题二:

P7404 家庭菜園 4

给定一个长为 N N N 的序列 A i A_i Ai, 你可以进行若干次操作:

  • 选定一个区间 [ L , R ] [L,R] [L,R],让这个区间里的数加 1 1 1

设经过这若干次操作后的序列为 B i B_i Bi ,那么你需要让 B i B_i Bi,满足下面这个要求:

  • 存在一个整数 k ∈ [ 1 , N ] k \in [1,N] k[1,N],满足对于子序列 A 1 = { A 1 , A 2 , ⋯   , A k } A_1=\{A_1,A_2,\cdots,A_k\} A1={A1,A2,,Ak} 为严格递增序列,对于子序列 A 2 = { A k , A k + 1 , ⋯   , A N } A_2=\{A_k,A_{k+1},\cdots,A_N\} A2={Ak,Ak+1,,AN},为严格递减序列。

你想知道最少需要多少次操作才能满足上面这个要求。

代码与解析

例题三:

P6070 Decrease 和 P4552 IncDec Sequence。

其实二维的差分和一维类似,可以看成是 n n n 个一维差分。cha[i][j]=cha[i][j]-cha[i][j-1],想要把矩阵上的数调成零,就相当于将 c h a i , j cha_{i,j} chai,j 变成 0 0 0

#include<bits/stdc++.h>
using namespace std;
long long n,m,k,f[5001][5001],a[5001][5001],sum,ans,tot;
int main(){
   cin>>n>>m>>k;
   while(m--){
   	long long x,y,z;
   	cin>>x>>y>>z;
   	a[x][y]=z;
   }
    for(long long i=1;i<=n;i++){
    	for(long long j=1;j<=n;j++){
    		f[i][j]=a[i][j]-a[i][j-1];
		}
	}
	for(long long i=1;i<=n-k+1;i++)
		for(long long j=1,num=0;j<=n-k+1;j++){
			num=f[i][j];
			if(num!=0){
				ans+=abs(num);
				for(long long t=i;t<=i+k-1;t++)
					f[t][j]-=num,f[t][j+k]+=num;
			}
		}
	for(long long i=1;i<=n;i++)
		for(long long j=1;j<=n;j++)
			if(f[i][j]){
			    cout<<"-1"<<endl;
			    return 0;
			}
	cout<<ans<<endl;
}
#include<bits/stdc++.h>
using namespace std;
long long A,B,ANS;
long long ans=1e20; 
const long long n=100001;
long long N,a[n],f[n];
int main() {
	cin>>N;
	for(long long i=1; i<=N; i++) {
		cin>>a[i];
		if(i!=1)f[i]=a[i]-a[i-1];
		ANS+=f[i];
		if(i!=1&&f[i]>0){
			B+=f[i];
		}
		else if(i!=1&&f[i]<0){
			A+=abs(f[i]);
		}
	}
	ans=max(A,B);
	cout<<ans<<endl;
	cout<<abs(ANS)+1<<endl;
   return 0;
}

例题四:

P3258 松鼠的新家

树上差分,对于每个节点存储 c h a i cha_i chai a i a_i ai,从根节点开始递归。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=3000001;
int a[MAXN],head[MAXN],tot,f[MAXN][30],final[MAXN],dep[MAXN],cha[MAXN];
struct shu {
	int next,to;
} e[MAXN];
int prepare(int x,int father) {
	dep[x]=dep[father]+1;
	for(int i=0; i<=25; i++) {
		f[x][i+1]=f[f[x][i]][i];
	}
	for(int i=head[x]; i; i=e[i].next) {
		int q=e[i].to;
		if(q!=father) {
			f[q][0]=x;
			prepare(q,x);
		}
	}
	return 0;
}
int add(int from,int to) {
	e[++tot].next=head[from];
	e[tot].to=to;
	head[from]=tot;
}
int LCA(int x,int y) {
	if(dep[x]<dep[y])swap(x,y);
	for(int i=20; i>=0; i--) {
		if(dep[f[x][i]]>=dep[y])x=f[x][i];
		if(x==y)return x;
	}
	for(int i=20; i>=0; i--) {
		if(f[x][i]!=f[y][i]) {
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
int chafen(int x,int &di,int father) {
	int tot=0;
	int pan=1;
	for(int i=head[x]; i; i=e[i].next) {
		int to=e[i].to;
		if(to!=father) {
			chafen(to,tot,x);
			pan=0;
		}
	}
	if(pan) {
		di+=cha[x];
		final[x]+=cha[x];
	} else {
		final[x]+=cha[x]+tot;
		di+=cha[x]+tot;
	}
	return 0;
}
int main() {
	int n,N;
	scanf("%d",&n);
	N=n;
	for(int i=1; i<=n; i++)scanf("%d",&a[i]);
	while(--n) {
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	n=N;
	prepare(1,0);
	int now=a[1];
	final[a[1]]++;
	for(int i=2; i<=N; i++) {
		int zhong=LCA(now,a[i]);
		if(zhong==now) {
			cha[now]--;
			cha[a[i]]++;
		} else if(zhong==a[i]) {
			cha[f[a[i]][0]]--;
			cha[f[now][0]]++;
		} else {
			cha[f[now][0]]++;
			cha[zhong]-=2;
			final[zhong]++;
			cha[a[i]]++;
		}
		now=a[i];
	}
	final[a[N]]--;
	int ter=0;
	chafen(1,ter,0);
	for(int i=1;i<=n;i++)cout<<final[i]<<endl;
}
举报

相关推荐

0 条评论