zoukankan      html  css  js  c++  java
  • 树的直径 练习

    随时会更新

    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
    ",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
    ",2*(n-1)-L1+1);
    		return 0;
    	}
    	modify(maxu),dp(1);
    	printf("%d
    ",2*n-L1-L2);
    }
    
  • 相关阅读:
    Link标签的media属性
    Moss2007ctx问题
    Moss2007 ListTemplate
    Html body的滚动条禁止与启用
    DOM的事件冒泡
    IE解析UL和LI的规则和问题
    AT&T汇编语言语法(一)(转)
    Linux 汇编语言开发指南 (转)
    Python 模块 jwt
    Excel2003和excel2007读取方法
  • 原文地址:https://www.cnblogs.com/Niuwadiandian/p/13959580.html
Copyright © 2011-2022 走看看