ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树上差分

2022-05-02 20:01:35  阅读:176  来源: 互联网

标签:10 int dif 差分 ++ 数组 树上


差分数组

我们令\(a[i]\)表示原数组
\(dif[i]\)表示差分数组
那么我们就有

\[\left\{ \begin{aligned} dif[0]&=a[0]\\ dif[i]&=a[i]-a[i-1],i>0 \end{aligned} \right. \]

那么\(a[i]=\sum_{k=0}^idif[k]\)

a[i] 4 6 4 3 6
dif[i] 4 2 -2 -1 -3

假设我们要将a[i]到a[k]的值全部加1,那么在差分数组中只需要++a[i],--a[k+1]。

树上差分

树上差分有两种,一种是点差分,另一种是边差分。

点差分

现在我们有如下一棵树

仍然是a[i]表示i结点的权值,dif[i]表示差分数组。
对应到树中就有dif[8]=a[8],dif[5]=a[5]-a[8],dif[4]=a[4]-a[5]-a[6]-a[7]
那么在dfs回溯时加上一句dif[i]+=dif[to] (to为i的子节点),dif[i]就转化为原数组了。
路径修改
假设我们要将8-->10这条路径的所有点的权值加x

我们只用++dif[8],++dif[10],--dif[lca(8,10)] (就是4号结点),--dif[father[lca(8,10)]] (就是2号结点),就可以了。
例题
P3128 [USACO15DEC]Max Flow P
参考代码

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
struct{
	int to,next;
}e[2*N];
int head[N],cnt;
int f[N][30],lg[N],dep[N];
int n,k,power[N];
inline void add(int a,int b){
	e[++cnt].to=b;
	e[cnt].next=head[a];
	head[a]=cnt;
}
void dfs(int a,int fa){
	dep[a]=dep[fa]+1;
	f[a][0]=fa;
	for(int i=1;i<=lg[dep[a]];++i)f[a][i]=f[f[a][i-1]][i-1];
	int to;
	for(int i=head[a];i;i=e[i].next){
		to=e[i].to;
		if(to==fa)continue;
		dfs(to,a);
	}
}
int lca(int a,int b){
	if(dep[a]<dep[b])swap(a,b);
	int d=dep[a]-dep[b];
	int t=0;
	while(d){
		if(d&(1<<t))a=f[a][t],d-=(1<<t);
		++t;
	}
	if(a==b)return b;
	for(int i=lg[dep[a]];i>=0;--i){
		if(f[a][i]!=f[b][i]){
			a=f[a][i];
			b=f[b][i];
		}
	}
	return f[a][0];
}
int ans;
void get(int a,int fa){
	int to;
	for(int i=head[a];i;i=e[i].next){
		to=e[i].to;
		if(to==fa)continue;
		get(to,a);
		power[a]+=power[to];//将差分数组变为原数组
	}
	ans=max(ans,power[a]);
}
int main(){
	scanf("%d%d",&n,&k);
	int a,b;
	for(int i=2;i<=n;++i)lg[i]=lg[i-1]+(1<<lg[i-1]+1==i);
	for(int i=1;i<n;++i){
		scanf("%d%d",&a,&b);
		add(a,b);
		add(b,a);
	}
	dfs(1,0);
	for(int i=1;i<=k;++i){
		scanf("%d%d",&a,&b);
		int l=lca(a,b);
		++power[a],++power[b],--power[l],--power[f[l][0]];//区间修改
	}
	get(1,0);
	printf("%d",ans);
	return 0;
}

边差分

将边的权值给子结点。

仍然是刚刚那条路经,由于修改的是边,权值给结点后将不包含lca(8,10)(4号结点)
那这个时候修改的操作为
++dif[8],++dif[10],dif[lca(8,10]-=2;

标签:10,int,dif,差分,++,数组,树上
来源: https://www.cnblogs.com/hetailang/p/16216504.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有