zoukankan      html  css  js  c++  java
  • bzoj1999 (洛谷1099) 树网的核——dfs

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1999

        https://www.luogu.org/problemnew/show/P1099

    “分析性质,O(n)扫描”

    看了半天才懂...发现自己对树的直径的相关知识太不熟了...

    这篇博客的讲解很详细:https://www.cnblogs.com/shenben/p/5895325.html

    说一下自己的理解:

    1.每个直径对答案的贡献是相同的;

      因为所有直径都相交,所以不妨考虑公共部分和分叉部分;

      会发现分叉部分的答案不如公共部分优,因为我们要取最小的偏心距,而分叉部分的偏心距一定会覆盖公共部分;

      所以只需要找出一条直径来做;

    2.一条直径上找最小偏心距,一定在“核”最长的时候找;

      这个很容易想到,因为长“核”一定不会劣于短“核”;

    3.对于一个“核”,有三个值可以更新它的偏心距:

      ①直径上的两端到“核”的两端的两个距离;

      ②“核”上所有点到直径外子树的最长距离;

      其中的①,许多“核”会重复求同样的值,所以干脆把它扩展到整条直径上的点到直径外子树的最大距离,求一遍即可;

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int const maxn=500005;
    int n,s,head[maxn],ct,dis[maxn],fa[maxn],l,l2;
    bool vis[maxn];
    struct N{
        int to,next,w;
        N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
    }edge[maxn<<1];
    void add(int x,int y,int z){edge[++ct]=N(y,head[x],z); head[x]=ct;}
    int rd()
    {
        int ret=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
        return ret*f;
    }
    void dfs(int x)
    {
        for(int i=head[x];i;i=edge[i].next)
        {
            int u=edge[i].to;
            if(vis[u]||u==fa[x])continue;
            dis[u]=dis[x]+edge[i].w;
            fa[u]=x; dfs(u);
        }
    }
    int main()
    {
        n=rd(); s=rd();
        for(int i=1,x,y,z;i<n;i++)
        {
            x=rd(); y=rd(); z=rd();
            add(x,y,z); add(y,x,z);
        }
        l=1; l2=1;
        dis[l]=0; fa[l]=0; dfs(l);
        for(int i=1;i<=n;i++)
            if(dis[i]>dis[l])l=i;
        dis[l]=0; fa[l]=0; dfs(l);
        for(int i=1;i<=n;i++)
            if(dis[i]>dis[l2])l2=i;
        int ans=0x3f3f3f3f,j=l2;
        for(int i=l2;i;i=fa[i])
        {
            while(fa[j]&&dis[i]-dis[fa[j]]<=s)j=fa[j];
            ans=min(ans,max(dis[j],dis[l2]-dis[i]));//min,max
        }
        for(int i=l2;i;i=fa[i])vis[i]=1;
        for(int i=l2;i;i=fa[i])dis[i]=0,dfs(i);
        for(int i=1;i<=n;i++)ans=max(ans,dis[i]);//max
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    使用url_for()时,会自动调用转换器的to_url()方法
    自定义flask转换器
    flask自有转换器:int、float、path。默认string
    flask中重定向所涉及的反推:由视图函数反推url
    mysqldump 命令使用
    PIX 防火墙
    MySQL 常用show 语句
    防火墙与入侵检测技术
    mysql DQL语言操作
    mysql 视图
  • 原文地址:https://www.cnblogs.com/Zinn/p/9199652.html
Copyright © 2011-2022 走看看