首页 > 其他分享 >树上差分

树上差分

时间:2023-09-08 22:55:59浏览次数:35  
标签:cnt int 差分 fa edge lca query 树上

树上差分与线性差分差不多,只不过是在树上进行差分,每次将两个点x和y的标志加1,将lca(x,y)和fa(lca(x,y))的标志减1,最后来一次深搜求和,就可以得到值了

下面给出几道例题

1.P3128 [USACO15DEC] Max Flow P

解析:

树上差分板子题,直接套班子,求完值后,求最大值即可

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e6+39+7;
int depth[N],f[N][21],n,head[N],tot,k,cnt[N],ans;
struct node{
	int u,v;
}edge[N<<1];
void add(int x,int y){
	edge[++tot].u=head[x];
	edge[tot].v=y;
	head[x]=tot;
}
void dfs(int u,int fa){
	depth[u]=depth[fa]+1;
	f[u][0]=fa;
	for(int i=1;(1<<i)<=depth[u];i++)f[u][i]=f[f[u][i-1]][i-1];
	for(int i=head[u];i;i=edge[i].u){
		if(edge[i].v==fa)continue;
		dfs(edge[i].v,u);
	}
}
int lca(int x,int y){
	if(depth[x]>depth[y])swap(x,y);
	for(int i=20;i>=0;i--)if(depth[y]-(1<<i)>=depth[x])y=f[y][i];
	if(x==y)return x;
	for(int i=20;i>=0;i--){
		if(f[x][i]==f[y][i])continue;
		x=f[x][i],y=f[y][i];
	}
	return f[x][0];
}
void dfss(int u,int fa){
	for(int i=head[u];i;i=edge[i].u){
		if(edge[i].v==fa)continue;
		dfss(edge[i].v,u);
		cnt[u]+=cnt[edge[i].v];
	}
}
int main(){
	cin>>n>>k;
	for(int i=1,a,b;i<n;i++)cin>>a>>b,add(a,b),add(b,a);
	dfs(1,0);
	for(int i=1,x,y,la;i<=k;i++){
		cin>>x>>y;
		la=lca(x,y);
		cnt[x]++;cnt[y]++;
		cnt[la]--;cnt[f[la][0]]--;
	}
	dfss(1,0);
	for(int i=1;i<=n;i++)ans=max(ans,cnt[i]);
	cout<<ans;
	return 0;
}

  

2.P3258 [JLOI2014] 松鼠的新家

解析:

树上差分板子题,每个点都会多算1次,所以,在深搜求完值之后,需要把每个数减1,依次输出即可

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e6+39+7;
int a[N],depth[N],f[N][21],n,head[N],tot,k,cnt[N],ans;
struct node{
	int u,v;
}edge[N<<1];
void add(int x,int y){
	edge[++tot].u=head[x];
	edge[tot].v=y;
	head[x]=tot;
}
void dfs(int u,int fa){
	depth[u]=depth[fa]+1;
	f[u][0]=fa;
	for(int i=1;(1<<i)<=depth[u];i++)f[u][i]=f[f[u][i-1]][i-1];
	for(int i=head[u];i;i=edge[i].u){
		if(edge[i].v==fa)continue;
		dfs(edge[i].v,u);
	}
}
int lca(int x,int y){
	if(depth[x]>depth[y])swap(x,y);
	for(int i=20;i>=0;i--)if(depth[y]-(1<<i)>=depth[x])y=f[y][i];
	if(x==y)return x;
	for(int i=20;i>=0;i--){
		if(f[x][i]==f[y][i])continue;
		x=f[x][i],y=f[y][i];
	}
	return f[x][0];
}
void dfss(int u,int fa){
	for(int i=head[u];i;i=edge[i].u){
		if(edge[i].v==fa)continue;
		dfss(edge[i].v,u);
		cnt[u]+=cnt[edge[i].v];
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1,a,b;i<n;i++){
		cin>>a>>b;
		add(a,b);
		add(b,a);
	}
	dfs(1,0);
	for(int i=1,LCA;i<n;i++){
		LCA=lca(a[i],a[i+1]);
		cnt[a[i]]++;cnt[a[i+1]]++;
		cnt[LCA]--;cnt[f[LCA][0]]--;
	}
	dfss(1,0);
	for(int i=2;i<=n;i++)cnt[a[i]]--;
	for(int i=1;i<=n;i++)cout<<cnt[i]<<'\n';
	return 0;
}

  

3.P2680 [NOIP2015 提高组] 运输计划

解析:

这道题使用了树上差分和记录路径的方法,预处理init数组,fa数组,dep数组等,进行求解,使用静态算法,存储每一次的问题,和两点之间的距离和lca,使用二分枚举时间,即可得到答案

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+39+7;
struct node{
	int x,y,lca,dis;
	bool operator <(const node &a)const{
		return dis<a.dis;
	}
}query[N];
struct edg{
	int to,next,w;
}e[N<<1];
int l,r,m,dep[N],fa[N][21],d[N],n,head[N],tot=-1,k,ans,init[N],cnt[N];
void add(int x,int y,int z){
	e[++tot]=(edg){y,head[x],z};
	head[x]=tot;
}
void dfs(int x,int father,int dis){
	dep[x]=dep[father]+1;
	fa[x][0]=father;init[x]=dis;
	for(int i=1;(1<<i)<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int i=head[x];~i;i=e[i].next){
		int y=e[i].to;
		if(y==father)continue;
		d[y]=d[x]+e[i].w;
		dfs(y,x,e[i].w);
	}
}
int lca(int x,int y){
	if(dep[x]>dep[y])swap(x,y);
	for(int i=20;i>=0;i--)if(dep[y]-(1<<i)>=dep[x])y=fa[y][i];
	if(x==y)return x;
	for(int i=20;i>=0;i--){
		if(fa[x][i]==fa[y][i])continue;
		x=fa[x][i];y=fa[y][i];
	}
	return fa[x][0];
}
void dfss(int u,int father){
	for(int i=head[u];~i;i=e[i].next){
		int y=e[i].to;
		if(y==father)continue;
		dfss(y,u);
		cnt[u]+=cnt[y];
	}
}
bool ok(int x){
	int num=0,now=0;
	for(int i=1;i<=n;i++)cnt[i]=0;
	for(int i=1;i<=m;i++){
		if(query[i].dis<=x)continue;
		cnt[query[i].x]++;cnt[query[i].y]++;
		cnt[query[i].lca]-=2;
		num++;
	}
	dfss(1,0);
	for(int i=1;i<=n;i++)if(cnt[i]==num)now=max(now,init[i]);
	return query[m].dis-now<=x;
}
int main(){
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1,x,y,z;i<n;i++){
		cin>>x>>y>>z;
		add(x,y,z);add(y,x,z);
	}
	dfs(1,0,0);
	for(int i=1,x,y;i<=m;i++){
		cin>>x>>y;
		query[i].lca=lca(x,y);
		query[i].dis=d[x]+d[y]-2*d[query[i].lca];
		r=max(r,query[i].dis);
		query[i].x=x;query[i].y=y;
	}
	sort(query+1,query+m+1);
	while(l<=r){
		int mid=(l+r)/2;
		if(ok(mid))r=mid-1;
		else l=mid+1;
	}
	cout<<l;
	return 0;
}

  

标签:cnt,int,差分,fa,edge,lca,query,树上
From: https://www.cnblogs.com/zhanghx-blogs/p/17688707.html

相关文章

  • 在方差分析摘要中,”F“、”P值“、”P值摘要“、 ”除手段非常显著性差异 (P < 0.00)
    在方差分析摘要中,“F”、“P值”、“P值摘要”、“除手段非常显著性差异(P<0.00)吗?”、"R平方"分别代表以下内容:“F”:F值是用来衡量组间差异与组内差异之比的统计量。F值越大,说明组间差异相对于组内差异越大,也就意味着不同组之间的差异更加显著。“P值”:P值是用来衡量观察......
  • UOJ33 树上 GCD
    UOJ传送门设\(f_{u,i}\)为\(u\)子树内深度为\(i\)的点的个数,在\(\operatorname{LCA}\)处计算答案。但是时间复杂度无法接受。考虑长剖,计算答案只用枚举到轻链长,先对轻儿子做一遍\(\text{Dirichlet}\)后缀和,重儿子的信息直接继承上来。但是我们没法查询深度\(\bmod......
  • 白盒AES和SM4实现的差分故障分析
    DFA攻击背景介绍传统的密码安全性分析环境被称为黑盒攻击环境,攻击者只能访问密码系统的输入与输出,但随着密码系统部署环境的多样化,该分析模型已经不能够反映实际应用中攻击者的能力。2002年,Chow等人[1]提出了白盒攻击环境的概念,该攻击环境中的攻击者对算法运行环境具备完全的控制......
  • 差分
    目录差分例题综合运用差分例题综合运用思维+差分牛客小白77C小Why的商品归位......
  • 第 360 场周赛 (二进制枚举、树上倍增)
    2833. 距离原点最远的点 本题要求最远的距离,所有‘_’必须全为左或全为右。利用前缀和的思想看看L多还是R多,最后加上_的数目就是答案。classSolution{public:intfurthestDistanceFromOrigin(stringmoves){intn=moves.size();inttt=0,l......
  • 2023牛客暑期多校练营6 A-Tree 树上背包+并查集
    2023牛客暑期多校练营6A-Tree树上背包+并查集题目链接题意:给出一棵树,节点为黑色或者白色,定义整棵树的贡献为,任意白点到任意黑点所经过路径上的最大边权之和,节点i原本颜色已给出,可以花费c[i]代价翻转节点i的颜色,问最大贡献是多少。做法:首先我们思考怎么处理最大边权的问题......
  • 前缀和与差分
    前缀和一维前缀和公式:\[s[i]=s[i-1]+a[i]\]模板:constintN=10000+10;intn,m;inta[N],s[N];intmain(){ scanf("%d%d",&n,&m);for(inti=1;i<=n;i++){scanf("%d",&a[i]);s[i]=s[i-1]......
  • 学习笔记413—python实现BP神经网络进行预测和误差分析(附源代码)
    python实现BP神经网络进行预测和误差分析(附源代码)反向传播算法也称为BP神经网络,是一种带有反馈的神经网络反向学习方法,它可以对神经网络的各层上的各个神经元的各个神经元之间的连接权重进行不断迭代修改,使神经网络将输入数据转换成期望的输出数据 BP神经网络的学习过程由正向......
  • 树上可持久化线段树
    例题传送门:Countonatree简要题意:有棵\(n\)个节点的树,每次点有个权值\(a_i\),每次询问给出\(u,v,k\),求\(u,v\)两个节点的简单路径上(包括\(u,v\))上第\(k\)小的点,保证数据有解,强制在线\(1\len,m\le10^5,a_i\in[1,2^{31}-1]\)首先,第\(k\)小就可以想到要可持久化线段树,动态开......
  • 树上启发式合并
    与其说树上启发式合并是一种算法,不如说是一种思想。它在于通过”小的并入大的“保证复杂度,从而解决很多看似无法做的问题。论纯用树上启发式合并的题很少,但是很多题却可以用树上启发式合并去解决。模板求解的问题往往具有如下性质:每颗子树都有要记录的信息,信息的数量和子树大......