zoukankan      html  css  js  c++  java
  • 直径——树直径的神奇性质

    description

    今有一边带权的树,求其直径,并求其所有直径经过公共边的条数.

    solution

    本题主要考察树的直径的性质.对于第一问,相信都能做,这里重点讨论第二问.这里,我们介绍两个引理:

     引理一:如果一棵树有多条直径,那么它们必有公共边.

    这里用反证法证明.假设树有两条直径(xi(x,y))(xi(u,v)),其长均为(d).若它们没有公共边,则设(xi(alpha,eta))为两条直径上距离最短的两个点间的路径,则有(max(|xi(x,alpha)|,|xi(y,alpha)|)geq frac{d}{2},max(|xi(u,eta)|,|xi(v,eta)|)geq frac{d}{2}),则有(max(|xi(x,alpha)|,|xi(y,alpha)|)+max(|xi(u,eta)|,|xi(v,eta)|)+|xi(alpha,eta)|>d),与(xi(x,y))(xi(u,v))是树的直径相矛盾,故树的多条直径间必有公共边.证毕.

     引理二:在引理一的基础上,树的多条直径间的公共边是连续的.

    这里交给读者证明.

    在这两个引理的基础上,我们可以先求出树直径的两个端点,再从左往右扫一遍,找出最右侧的不可能成为必经边的端点.再从右往左扫一遍,找出最左侧不可能成为必经边的点.最后统计答案即可.具体见代码.

    code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    #include<map>
    #define R register
    #define next jfklslk
    #define debug puts("mlg")
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    inline ll read();
    inline void write(ll x);
    inline void writesp(ll x);
    inline void writeln(ll x);
    ll n;
    ll head[1000000],next[1000000],tot,to[1000000];
    ll w[1000000];
    inline void add(ll x,ll y,ll z){to[++tot]=y;next[tot]=head[x];head[x]=tot;w[tot]=z;}
    ll l,r;
    ll maxn,d[1000000],pre[1000000];
    inline void dfs1(ll x,ll fa,ll deep,bool type){
    	d[x]=deep;
    	pre[x]=fa;
    	if(d[x]>maxn){
    		maxn=d[x];
    		if(type) r=x;
    		else l=x;
    	}
    	for(R ll i=head[x],ver;i;i=next[i]){
    		ver=to[i];
    		if(ver==fa) continue;
    		dfs1(ver,x,deep+w[i],type);
    	}
    }
    bool vis[1100000],book[1100000];
    ll dis[1100000],val[1100000];
    ll nxt[1100000];
    ll maxx;
    inline void dfs2(ll x,ll fa,ll deep){
    	dis[x]=deep;
    	maxx=max(maxx,dis[x]);
    	for(R ll i=head[x],ver;i;i=next[i]){
    		ver=to[i];
    		if(ver==fa||book[ver]) continue;
    		dfs2(ver,x,deep+w[i]);	
    
    	}
    }
    ll l1,r1;
    ll ans;
    ll cnt;
    int main(){
    	n=read();
    	for(R ll i=1,x,y,z;i<n;i++){
    		x=read();y=read();z=read();
    		add(x,y,z);add(y,x,z);
    	}
    	dfs1(1,0,0,0);
    	maxn=0;
    	dfs1(l,0,0,1);
    	writeln(maxn);
    	for(R ll x=r;x;x=pre[x]) book[x]=true,nxt[pre[x]]=x,++cnt;
    	for(R ll x=r;x;x=pre[x]){
    		maxx=0;
    		dfs2(x,0,0);
    		val[x]=maxx;
    	}
    	for(R ll x=l;x;x=nxt[x]){
    		if(val[x]==maxn-d[x]){
    			r1=x;break;
    		}
    	}
    	for(;r1!=0;r1=pre[r1]){
    		
    		if(val[r1]==d[r1])	break;	
    		++ans;
    	}
    	writeln(ans);
    }
    inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
    inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
    inline void writesp(ll x){write(x);putchar(' ');}
    inline void writeln(ll x){write(x);putchar('
    ');}
    
  • 相关阅读:
    android EditText 软键盘 一些总结
    Activity的4种加载模式最佳解答及Intent常用标识
    Android App监听软键盘按键的三种方式
    解决ScrollView下嵌套ListView、GridView显示不全的问题(冲突)
    Android使用WindowManager实现悬浮窗口
    android 设置软键盘默认为26位软键盘
    android:configChanges属性总结
    空腹吃香蕉对身体好吗?哪些水果不宜空腹吃
    冒泡排序,选择排序,二分法
    Android:内存优化的一些总结
  • 原文地址:https://www.cnblogs.com/ylwtsq/p/13426936.html
Copyright © 2011-2022 走看看