zoukankan      html  css  js  c++  java
  • BZOJ 3124: [Sdoi2013]直径

    题目
    简述题意:求直径的必须边。

    首先,可通过两次dfs/bfsdfs/bfs,求出一条直径这里不赘述。

    引理:两条直径必有公共点。
    证明显然:
    假设两条直径无公共点,那么由于树的连通性,我们在把这两条直径连起来一定更长,
    与直径的最长性矛盾。

    之后我们画图找一下,对于两条直径下的情况。
    在这里插入图片描述
    我们只要求一下满足第一种情况的深度最大值uu,再求出满足第二种情况的深度最小值vv,
    vuv-u,即为答案.特殊地,初始化u=0,v=dep[q]u=0,v=dep[q].

    这是否适用于所有情况呢?答案是显然的。
    由于直径必交,而必须边的定义又是属于任意直径,
    所以我们只要枚举直径上的点,看是否有合法分叉(能在直径中).
    按照上面的求法,我们能保证不违反必须边的定义,同时最大,所以答案正确。

    #include<map>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #define fir first
    #define sec second
    #define lc (x<<1)
    #define rc (x<<1|1)
    #define g getchar()
    #define mk make_pair
    #define pi pair<int,int>
    using namespace std;
    typedef long long ll;
    const int N=2e5+10;
    template<class o>void qr(o&x) {
    	char c=g;int f=1;x=0;
    	while(!isdigit(c)){if(c=='-')f=-1;c=g;}
    	while(isdigit(c))x=x*10+c-'0',c=g;
    	x*=f;
    }
    template<class o>void write(o x) {
    	if(x/10)write(x/10);
    	putchar(x%10+'0');
    }
    template<class o>void pri(o x) {
    	if(x<0)x=-x,putchar('-');
    	write(x);puts("");
    }
    
    int n,m,dep[N],fa[N];
    ll d[N],f[N];
    struct edge{int y,next,d;}a[N<<1];int len,last[N];
    void ins(int x,int y,int d) {a[++len]=(edge){y,last[x],d};last[x]=len;}
    
    void dfs(int x,int &t) {
    	f[x]=0;//d由上到下传递,f反之 
    	for(int k=last[x],y,z;k;k=a[k].next) {
    		y=a[k].y; z=a[k].d; if(y==fa[x]) continue;
    		fa[y]=x; dep[y]=dep[x]+1; d[y]=d[x]+z;
    		dfs(y,t); if(d[y]>d[t]) t=y; f[x]=max(f[x],f[y]+z);
    	}
    }
    
    int u,v,p,q,sta[N],top;//直径有关信息:p,q为直径端点 
    bool in[N];
    
    void find() {
    	for(int i=1;i<=n;i++) in[sta[i]]=1;
    	while(top) {
    		int x=sta[top--];
    		for(int k=last[x],y,z;k;k=a[k].next) {
    			y=a[k].y; z=a[k].d; if(in[y]) continue;
    			if(f[y]+z==f[x]) v=min(v,dep[x]);
    			if(f[y]+z==d[x]) u=max(u,dep[x]);
    		}
    	}
    	pri(v-u);
    }
    
    int main() {
    	qr(n);
    	for(int i=1,x,y,z;i<n;i++)	
    		qr(x),qr(y),qr(z),ins(x,y,z),ins(y,x,z);
    	fa[1]=0; d[1]=0; dep[1]=1; dfs(1,p=1);
    	fa[p]=0; d[p]=0; dep[p]=1; dfs(p,q=p);
    	pri(d[q]); v=dep[q]; u=1;
    	do {
    		sta[++top]=q;
    		q=fa[q];
    	} while(q);
    	find(); return 0;
    }
    	
    
  • 相关阅读:
    在linux写一个shell脚本用maven git自动更新代码并且打包部署
    maven mvn 命令行 编译打包
    linux修改文件为可执行文件
    shell脚本中根据端口号kill对应的应用进程
    linux如何查看端口被哪个进程占用?
    LINUX中如何查看某个端口是否被占用
    The JAVA_HOME environment variable is not defined correctly的错误
    Linux配置Java环境变量
    requests
    https://www.cnblogs.com/zheting/category/1086753.html
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373866.html
Copyright © 2011-2022 走看看