1.求树的直径与两个端点。
(两遍dfs,son记录端点。)
CF1294F
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+50;
struct node
{
int to,next;
int wei;
}edge[2*maxn];
int tot;
int head[maxn];
void edge_init()
{
memset(head,0,sizeof(head));
tot=0;
}
void add(int u,int v,int wei)
{
edge[++tot].to=v;
edge[tot].next=head[u];
edge[tot].wei=wei;
head[u]=tot;
}
int n;
int son[maxn];
int d[maxn];
int vis[maxn];
int tmp1[maxn];
int tmp2[maxn];
void dfs(int x,int fa)
{
vis[x]=1;
son[x]=x;
for(int i=head[x];i;i=edge[i].next)
{
int y=edge[i].to;
if(y==fa) continue;
dfs(y,x);
if(d[y]+edge[i].wei>d[x])
{
d[x]=d[y]+1;
son[x]=son[y];
}
}
// cout<<x<<"..."<<d[x]<<endl;
return;
}
void bfs(int x)
{
vis[x]=1;
queue<int> que;
d[x]=0;
que.push(x);
while(!que.empty())
{
int x=que.front();
que.pop();
for(int i=head[x];i;i=edge[i].next)
{
int y=edge[i].to;
if(vis[y]) continue;
vis[y]=1;
d[y]=d[x]+1;
que.push(y);
}
}
return;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b,1);
add(b,a,1);
}
int beg,end;
dfs(1,0);beg=son[1];
for(int i=1;i<=n;i++)
{
vis[i]=d[i]=0;
}
// cout<<beg<<"--"<<endl;
dfs(beg,0);end=son[beg];
for(int i=1;i<=n;i++)
{
vis[i]=d[i]=0;
}
bfs(beg);
for(int i=1;i<=n;i++)
{
tmp1[i]=d[i];
}
for(int i=1;i<=n;i++)
{
vis[i]=d[i]=0;
}
bfs(end);
for(int i=1;i<=n;i++)
{
tmp2[i]=d[i];
}
int pos=0;
for(int i=1;i<=n;i++)
{
// cout<<tmp1[i]<<"--"<<tmp2[i]<<endl;
if(tmp1[i]+tmp2[i]>tmp1[pos]+tmp2[pos]&&i!=beg&&i!=end)
pos=i;
}
int ans=(tmp1[end]+tmp1[pos]+tmp2[pos])/2;
printf("%d\n%d %d %d\n",ans,beg,end,pos);
return 0;
}
2.换根dp求解树上每一个点为根时的最长链。
(dp,dp0是子树中最长值,dp1是子树中次长值,dp2是答案)。
3.最大或者最小的点覆盖或者边覆盖。
4.树的重心
1.树的重心是对于树上每一个点作为根节点时的最大子树数量的最小值的那个点。
2.树的重心当根时所有的子树的大小都不超过整棵树的一半。
3.树上所有点到重心的距离和是最小的,如果有两个重心,那么到这些重心的距离是一样的。
求重心代码:
int siz[maxn];int mx[maxn];
int val[x];
void dfs(int x,int fa)
{
siz[x]=1;//如果每个点带权,就写成siz[x]=val[x];val[x]就是每个点的权值。
for(int i=0;i<edge[x].size();i++)
{
int y=edge[x][i];
if(y==fa) continue;
dfs(y,x);
siz[x]+=siz[y];
mx[x]=max(mx[x],siz[y]);
}
mx[x]=max(mx[x],n-siz[x]);
return;
}
dfs(1,0);
int rot;
int mxx=1000000009;
for(int i=1;i<=n;i++)
{
if(mx[i]<mxx)
{
rot=i;mxx=mx[i];
}
}
NOTE:该代码是求不带权的树的重心,带权的树的重心也是求子树最大数最小的点。