经典例子如下:
lca
树上差分
树的重心
树的直径
树的中心
树链剖分
最近公共祖先
P3379 【模板】最近公共祖先(LCA) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
简单模板,过了无数遍
P3128 [USACO15DEC] Max Flow P - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
树上差分
就差一点
#include<iostream>
using namespace std;
int n,k;
int dep[50001];
int fa[50001][21];
int a[50001];
int b[50001];struct EDGE{int next;
int to;}edge[100001];
int head[50001];
int tot=0;
void addedge(int u,int v){
edge[++tot].next=head[u];
edge[tot].to=v;
head[u]=tot;
}
void dfs(int u,int father){dep[u]=dep[father]+1;
for(int i=1;(1<<i)<=dep[u];i++){fa[u][i]=fa[fa[u][i-1]][i-1];
}for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;if(v==father)continue;fa[v][0]=u;dfs(v,u);
}}void dfss(int u,int father){cout<<"现在u,fa"<<u<<" "
//a[u]=子树a+差分ba[u]=b[u];for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;cout<<"现在v"<<v<<endl;if(v==father)continue;dfs(v,u);a[u]+=a[v];for(int i=1;i<=n;i++){cout<<a[i]<<" ";}cout<<endl;
}}int lca(int x,int y){if(dep[x]<dep[y])swap(x,y);for(int i=20;i>=0;i--){if(dep[fa[x][i]]>=dep[y])x=fa[x][i];if(x==y)return x;
}for(int i=20;i>=0;i--){if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}
}return fa[x][0];}int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)head[i]=-1;for(int i=1;i<=n-1;i++){int u,v;cin>>u>>v;addedge(u,v);addedge(v,u);
}dfs(1,0);while(k--){
int x,y;
cin>>x>>y;
int mf=lca(x,y);b[x]++;
b[y]++;
b[mf]--;
if(mf != 1) b[fa[mf][0]]--;}cout<<"现在检验5的边";
for(int i=head[5];~i;i=edge[i].next)
{
cout<<edge[i].to<<" ";}
cout<<"检验结束"<<endl;dfss(1,0);
int ans=0;for(int i=1;i<=n;i++){ans=max(ans,a[i]);
}cout<<ans;}
P5002 专心OI - 找祖先 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
n^3 tle
树的直径
树的直径两种求法_求树的直径-CSDN博客
法一:dfs找距离任意一点最远的点u
dfs找距离u最远的一点v
uv即为直径
只能用于没有付权边
void dfs(int u,int father){for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==father)continue;d[v]=d[u]+edge[i].w;
dfs(v,u);
}}int main(){
dfs(1,0);
//选出d[s]最大
dfs(s,0);
//选出d[v]最大
cout<<d[v];}
法二:
某一点的最短路和次短路
某一点到其子节点的最长距离和次长距离,加起来就是直径
void dfsdp(int u,int father)
{for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(v==father)continue;dfsdp(v,u);if(d1[u]<d1[v]+w){d2[u]=d1[u];d1[u]=d1[v]+w;}else if(d2[u]<d1[v]+w){
d2[u]=d1[v]+w;}
}}
Cow Marathon - OpenJ_Bailian 1985 - Virtual Judge (vjudge.net.cn)
#include<iostream>
using namespace std;
int n,m;struct EDGE{
int next;
int to;
int w;}edge[80001];
int head[40001];
int d[40001];
int tot=0;
void addedge(int u,int v,int w){
edge[++tot].next=head[u];
edge[tot].to=v;
edge[tot].w=w;
head[u]=tot;
}void dfs(int u,int father){for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;if(v==father)continue;d[v]=d[u]+edge[i].w;dfs(v,u);
}}int main(){cin>>n>>m;
for(int i=1;i<=n;i++)head[i]=-1;
for(int i=1;i<=m;i++){int u,v,w;char s;cin>>u>>v>>w>>s;addedge(u,v,w);addedge(v,u,w);
}dfs(1,0);
int xuan1=-1;int xuan2=0;
for(int i=1;i<=n;i++){if(d[i]>xuan2){xuan1=i;xuan2=d[i];}d[i]=0;}dfs(xuan1,0);
xuan1=-1;xuan2=0;for(int i=1;i<=n;i++){if(d[i]>xuan2){xuan1=i;xuan2=d[i];}}
cout<<xuan2;}
树的中心
树的重心是节点数
树的重心是路径长度
到别的点的最长距离最小的点
-》枚举每个点
、子树的最长距离直径中有板子 +、向上走的
//走下面的最长
void dfsd12(int u,int father){
for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(v==father)continue;dfsd12(v,u);if(d1[u]<d1[v]+w){d2[u]=d1[u];d1[u]=d1[v]+w;p1[u]=v;//path}else if(d2[u]<d1[v]+w){d2[u]=d1[v]+w;}
}
}//走上面的最长
void dfsup(int u,int father){
for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(v==father)continue;if(p1[u]==v){up[v]=max(d2[u],up[u])+w;}else {up[v]=max(d1[u],up[u])+w;}dfsup(v,u);
}}
1073. 树的中心 - AcWing题库
//走下面的最长
void dfsd12(int u,int father){
for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(v==father)continue;dfsd12(v,u);if(d1[u]<d1[v]+w){d2[u]=d1[u];d1[u]=d1[v]+w;p1[u]=v;//path}else if(d2[u]<d1[v]+w){d2[u]=d1[v]+w;}
}
}//走上面的最长
void dfsup(int u,int father){
for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(v==father)continue;if(p1[u]==v){up[v]=max(d2[u],up[u])+w;}else {up[v]=max(d1[u],up[u])+w;}dfsup(v,u);
}}