差分技巧学习指南

前置芝士

二维差分数组

\(1≤q≤100000,1≤n,m≤10^3,1≤x1≤x2≤n,1≤y1≤y2≤m,1≤a_{i,j},c≤10^5\)

void solve(){
    int n,m,q;
    cin>>n>>m>>q;
    vector<vector<ll>> a(n+1,vector<ll>(m+1,0));
    vector<vector<ll>> b(n+2,vector<ll>(m+2,0));
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++) cin>>a[i][j];
    while(q--){
    	int x0,y0,x1,y1,c;
    	cin>>x0>>y0>>x1>>y1>>c;
        // cout<<x0<<y0<<x1<<y1<<c<<endl;
	//下标从1开始
    	b[x0][y0]+=c;
    	b[x0][y1+1]-=c;
    	b[x1+1][y0]-=c;
    	b[x1+1][y1+1]+=c;
    }
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		b[i][j]+=b[i][j-1]+b[i-1][j]-b[i-1][j-1];
    		cout<<b[i][j]+a[i][j]<<" ";
    	}
    	cout<<endl;
    }
}

三维差分数组

树上差分

要求对树上的一段路径进行操作,并询问某个点或某条边被经过的次数,树上差分就可以派上用场了。

对路径上的重要节点进行修改(而不是暴力全改),作为其差分数组的值,最后在求值时,利用dfs遍历求出差分数组的前缀和,就可以达到降低复杂度的目的。

点差分

设将两点u,v之间路径上的所有点权增加x,o=LCA(u,v),o的父亲节点为p,则操作如下:

diff[u]+=x,diff[v]+=x,diff[o]-=x,diff[p]-=x;

现要将2,3之间路径上的所有点的权值增加3,设原权值均为0。

img

边差分

将两点u,v之间路径上的所有边权增加xo=LCA(u,v),以每条边两端深度较大的节点存储该边的差分数组

diff[u]+=x,diff[v]+=x,diff[o]-=2*x;

img

posted @ 2023-10-17 23:53  White_Sheep  阅读(8)  评论(0编辑  收藏  举报