树论
树的基本概念
1.树是无环图,自己的最小生成树。 \ 2.N个节点,N-1条边的联通无向图(无环),只有一条路。
有根树
1.存储
for(int i=1;i<=n;i++)
{
cin>>x>>y>>z;
e[x].push_back({y,z});
e[y].push_back({x,z});
fa[y]=x;//记录父亲节点
}
树的遍历
判断父亲结点:
1.使用vis数组
void dfs(int u)
{
for(auto i:e[u)
{
int v=i.v,w=i.w;
if(!vis[v])
{
vis{v]=1
dfs(v)
}
}
}
2.父亲结点传入信息
基础模板
void dfs(int u,int fa)
{
if(dis>d)
return ;
for(auto i:e[u])
{
int v=i.v,w=i.w;
if(v==fa)
{
continue;
}
dfs(v,u);
}
}
变形1
int size[N];//统计子树的结点个数
void dfs(int u,int fa)
{
size[u]=1;//统计子树的结点个数
if(dis>d)
return ;
for(auto i:e[u])
{
int v=i.v,w=i.w;
if(v==fa)
{
continue;
}
dfs(v,u);
size[u]+=size[v];//统计子树的结点个数
abs(size[u]*2-n)*w;
}
}//P2052 [NOI2011] 道路修建为例
变形2
int size[N];//统计子树的结点个数
void dfs(int u,int fa)
{
size[u]=1;//统计子树的结点个数
if(dis>d)
return ;
for(auto i:e[u])
{
int v=i.v,w=i.w;
if(v==fa)
{
continue;
}
dfs(v,u);
size[u]+=size[v];//统计子树的结点个数
abs(size[u]*2-n)*w
}
if(size[u]==k)//判断结点数量是否为K
{
cnt++;
size[u]=0;
}
}//P3915 树的分解
遍历特点:边数 * 2=路径长度
树的重心
某个点被拿出后,原来的树会被分为子结点数+1(父亲结点以上) 棵树
定义:拿掉的一个点后能使所有分出的子树中的结点数最大的结点数最小,也就是最平均
特点
1.最多只有两个重心且两个重心相邻 \ 2.以重心为根的子树不超过原树的一半 \ 3.一个或两个重心到各个结点的距离和最小 \ 4.两棵树通过一条边相连,新树的重心在连接原来两棵树的重心的路径上
代码实现
int size[N],z1,z2;
void dfs(int u,int fa)
{
size[u]=1;//统计子树的结点个数
for(auto i:e[u])
{
int v=i.v,w=i.w;
if(v==fa)
{
continue;
}
dfs(v,u);
size[u]+=size[v];//统计子树的结点个数
w[u]=max(w[u],size[v]);//下方子树max
}
w[u]=max(w[u],n-size[u]);//上方子树max
if(w[u]<=n/2)
{
if(z1)
{
z2=u;
}
else
{
z1=u;
}
}
}
变形
int size[N],z1,z2;
void dfs(int u,int fa)
{
size[u]=1;//统计子树的结点个数
for(auto i:e[u])
{
int v=i.v,w=i.w;
if(v==fa)
{
continue;
}
dfs(v,u);
size[u]+=size[v];//统计子树的结点个数
w[u]=max(w[u],size[v]);//下方子树max
}
w[u]=max(w[u],sum-size[u]);//上方子树max
if(w[u]<=sum/2)//点有权值
{
if(z1)
{
z2=u;
}
else
{
z1=u;
}
}
}
树的重心的应用
1.
void dfs(int x,int f)
{
size[x]=1;
for(auto i:e[x])
{
if(i==1) continue;
dfs(i,x);
size[x]+=size[i];//不能放dfs前
w=max(x,size[i]);
}
w=max(w,n-size[x]);
if(w<=n/2)
{
x=
}
}//适用于医院设置等问题
2.
int dis[N];
dis[st]=0;//st 为起点
void dfs(int x,int f)
{
for(auto i:e[x])
{
int v=i.v,w=i.w;//i为结构体
if(i==1) continue;
dis[i]=dis[x]+w;
ans=max(ans,dis[v]);//遍历用的是i的信息,否则层级会错乱
dfs(i,x);
}
}
树的直径
1.定义:树的两点之间最远的距离(不一定要过根节点)
2.求法
1.做两次dfs/bfs——边权都是非负值、代码简单
16:13
2.树形DP——任意边权值、代码难写
树的中心
1.定义:到其他所有点的最大距离最小的点(一定在树的直径上)
2.以树的中心为整棵树的根时,从根到叶子节点的最长路径最短(树最浅)
3.当树的边权为1时,树的中心一定为树的直径的中点