树的直径 练习

随时会更新

P4408

根据题意可以发现构成的图是一棵树。
然后可以发现行走路径是从 C 到距离较近的 A 或 B 点,再走完 A-B 路径,所以对于 A-B 路径,其长度与 C 的位置是无关的,所以他有一个固定的上限,在根据树的直径的性质,可以将其 A-B 确定为树的直径,之后我们要做的就是处理出直径一端点 A 与所有点的距离,另一端点 B 与所有点的距离,枚举一遍 n 更新答案即可。
时间复杂度 \(O(n)\)

#include <cstdio>
#include <algorithm>
#define int long long 

const int N=400070;
struct Tree{ int to,nxt,w; }e[N];
int n,m,cnt,maxdis,maxu,A,B;
int head[N],d[2][N];
void dfs(int u,int fa,int dis){
	if(dis>maxdis) maxdis=dis,maxu=u;
	for(int i=head[u],v;i;i=e[i].nxt){
		v=e[i].to;if(v==fa) continue;
		dfs(v,u,dis+e[i].w);
	}
}
void DFS(int u,int fa,int k){
	for(int i=head[u],v;i;i=e[i].nxt){
		v=e[i].to;if(v==fa) continue;
		d[k][v]=d[k][u]+e[i].w;
		DFS(v,u,k);
	}
}
void add(int from,int to,int val){e[++cnt].to=to,e[cnt].w=val,e[cnt].nxt=head[from],head[from]=cnt;}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1,u,v,w;i<=m;++i){
		scanf("%lld%lld%lld",&u,&v,&w);
		add(u,v,w),add(v,u,w);
	}
	dfs(1,0,0),maxdis=0,A=maxu,dfs(A,0,0),B=maxu,DFS(A,0,0),DFS(B,0,1);
	int ans=0;
	for(int i=1;i<=n;++i)
		ans=std::max(ans,maxdis+std::min(d[0][i],d[1][i]));
	printf("%lld\n",ans);
}

P3639

\(k = 0\) 时,因为要回到最终的起点,根据树的性质,我们可以迅速地得到答案为 \(2*(n-1)\)
\(k = 1\) 时,这条添加的边必须要遍历一遍,根据树的性质,添加一条边后树上肯定形成了一个环,所以整个环只需要遍历一遍,那我们要是减少的代价最多,根据树的性质,我们就需要找到树的直径,将两端相连,记直径的长度为 L1,
这样我们此时的答案是 \(2*(n-1)-L1+1\)
\(k = 2\) 时,根据之前的性质,我们原来的图中出现了两个环,若两个环没有重合的部分,那么我们的结论可以类比上题,但如果有重合的部分,此时我们肯定需要将重合的部分给去除掉,为了做到这一点,要做的就是将第一遍遍历得到的直径上所有边权改为 -1,再在新图上找一条新的直径,记直径的长度为 L2,很显然,答案是 \(2*(n-1)-L1+1-L2+1\)

#include <cstdio>
#include <algorithm>
#include <map>

const int N=200070;
const int inf=1e9;
struct Tree{ int to,nxt; }e[N];
bool vis[N];
std::map<int,int>mp[N];
int n,k,cnt,maxdis,maxu,L1,L2;
int head[N],f[N],pre[N],d[N];
void add(int from,int to){e[++cnt].to=to,e[cnt].nxt=head[from],head[from]=cnt;}
void dfs(int u,int fa,int dis){
	if(dis>maxdis) maxdis=dis,maxu=u;
	for(int i=head[u],v;i;i=e[i].nxt){
		v=e[i].to;if(v==fa) continue;
		dfs(v,u,dis+1);
	}
}
void dfs2(int u,int fa,int dis){
	if(dis>maxdis) maxdis=dis,maxu=u;
    pre[u]=fa;
	for(int i=head[u],v;i;i=e[i].nxt){
		v=e[i].to;if(v==fa) continue;
		dfs2(v,u,dis+1);
	}
}
int get(){
	dfs(1,0,0),maxdis=0,dfs2(maxu,0,0);
	return maxdis;
}
void modify(int u){
	if(!u) return;
	mp[u][pre[u]]=mp[pre[u]][u]=-1;
	modify(pre[u]);
}
void dp(int u){
	vis[u]=1;
	for(int i=head[u],v;i;i=e[i].nxt){
		v=e[i].to;if(vis[v]) continue;
		dp(v),L2=std::max(L2,f[v]+f[u]+mp[u][v]),f[u]=std::max(f[u],f[v]+mp[u][v]);
	}
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1,u,v;i<n;++i){
		scanf("%d%d",&u,&v);
		add(u,v),add(v,u);
		mp[u][v]=mp[v][u]=1;
	}
	L1=get();
	if(k==1){
		printf("%d\n",2*(n-1)-L1+1);
		return 0;
	}
	modify(maxu),dp(1);
	printf("%d\n",2*n-L1-L2);
}
posted @ 2020-11-11 17:02  牛蛙丶丶  阅读(101)  评论(1编辑  收藏  举报