Luogu_P1099 树网的核 树的直径

Luogu_P1099 树网的核

### 树的直径

题目链接
题面好长,都不想看
又是明明显显的树的直径的题

可以有很多种答案更新方法:

方法一

可以\(O(n^2)\)的枚举核的一端\(p\)得出\(p+s\)和离他们的最远的点

方法二

可以二分偏心距,\(O(nlogsum)\)

方法三

求出最长链,然后分别求他们的最远点的距离\(fr[i]\)
\(a[i]\)存的是链的点编号
然后偏心距就是\(\max(fr[a[k]]\max(d[a[i]],d[a[1]]-d[a[j]]))\)
再娶个\(\min\)就\(O(n)\)解决了。


代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
int fs,d[maxn],n,s,head[maxn],tot,fa[maxn],v[maxn],a[maxn],cnt;
int fr[maxn];
struct node{
    int nxt,to,dis;
    #define nxt(x) e[x].nxt
    #define to(x) e[x].to
    #define dis(x) e[x].dis
}e[maxn<<1];
inline void add(int from,int to,int dis){
    to(++tot)=to;dis(tot)=dis;
    nxt(tot)=head[from];head[from]=tot;
}
void dfs(int x){
    v[x]=1;
    for(int i=head[x];i;i=nxt(i)){
        if(v[to(i)]) continue;
        fa[to(i)]=x;
        d[to(i)]=d[x]+dis(i);
        fs= d[to(i)]>d[fs] ? to(i) : fs;
        dfs(to(i));
    }
    v[x]=0;
}
inline void getd(){
    fs=1;
    dfs(1);
    d[fs]=0;memset(fa,0,sizeof(fa));
    int fs1=fs;fs=1;
    dfs(fs1);memset(v,0,sizeof(v));
    while(fs!=fs1){
        v[fs]=1;
        a[++cnt]=fs;
        fs=fa[fs];
    }
    v[fs1]=1;a[++cnt]=fs1;
}
void getfr(int x){
    v[x]=1;
    for(int i=head[x];i;i=nxt(i)){
        if(v[to(i)]) continue;
        getfr(to(i));
        fr[x]=max(fr[x],fr[to(i)]+dis(i));
    }
}
int main()
{
    scanf("%d%d",&n,&s);
    for(int x,y,z,i=1;i<n;i++){
        scanf("%d%d%d",&x,&y,&z);add(x,y,z);add(y,x,z);
    }
    getd();
    for(int i=1;i<=cnt;i++) getfr(a[i]);
    int ans=0x7ffffff,maxfr=0;
    for(int i=1;i<=cnt;i++) maxfr=max(maxfr,fr[a[i]]);
    for(int j=cnt,i=cnt;i;i--){
        while(j && d[a[j]]-d[a[i]] <= s) j--;
        ans=min(ans,max(maxfr,max(d[a[i]],d[a[1]]-d[a[j+1]])));
    }
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/ChrisKKK/p/11607033.html

时间: 2024-10-09 07:24:38

Luogu_P1099 树网的核 树的直径的相关文章

树网的核[树 floyd]

描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和.我们称d(a, b)为a, b两结点间的距离. D(v, P)=min{d(v, u), u为路径P上的结点}. 树网的直径:树网中最长的路径成为树网的直径

【DFS好题】BZOJ1999- [Noip2007]Core树网的核(数据加强版)

NOIP的数据好水,一开始有好几个错结果NOIP数据就水过了?? [题目大意] 求无根树的直径上一段不超过S长的链,使得偏心距最小.具体概念见原题. [思路] 首先明确几个性质: (1)对于树中的任意一点,距离其最远的点一定是树的直径的某一端点. (2)所有的直径是等价的,即任意一条所能求出的该最小偏心距相等. 于是我们可以用两次dfs求出直径.任取一个点找到离它最远的点r,再从r找到距离它最远的点l.l到r的路径就是直径. 显然在长度不超过S的情况下,链最长最好.在l到r上维护尽可能长的链,找

[bzoj1999]树网的核

从下午坑到网上..原来noip的数据真是太弱了,若干的地方写挂结果还随便过= = 最坑的就是网上有些题解没考虑周全...然而noip数据太弱了noip数据太弱了noip数据太弱了 第一步是找直径,用两次bfs(或者dfs,Linux下系统栈挺大的..)解决.找出其中一条直径就可以了,虽然蒟蒻不会证明但是看起来似乎挺有道理的 要看证明的话可以看这个题解:http://trinklee.blog.163.com/blog/static/238158060201411175015709/ 直径上的路径

noip2007 树网的核

P1099 树网的核 112通过 221提交 题目提供者该用户不存在 标签动态规划树形结构2007NOIp提高组 难度提高+/省选- 提交该题 讨论 题解 记录 题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边

树网的核(codevs 1167)题解

[问题描述] 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和.我们称d(a, b)为a, b两结点间的距离. D(v, P)=min{d(v, u), u为路径P上的结点}. 树网的直径:树网中最长的路径成为树

NOIP 2007树网的核

题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和.我们称d(a, b)为a, b两结点间的距离. D(v, P)=min{d(v, u), u为路径P上的结点}. 树网的直径:树网中最长的路径成为树网的

[BZOJ1999][codevs1167][Noip2007]Core树网的核

试题描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T为树网(treenetwork),其中V, E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a,b)表示以a,b为端点的路径的长度,它是该路径上各边长度之和.我们称d(a,b)为a,b两结点间的距离. 一点v到一条路径P的距离为该点与P上的最近的结点的距离: d(v,P)=min{d(v,u),u为路径P上的结

poj 1985 Cow Marathon 【树的直径】

题目:poj 1985 Cow Marathon 题意:给出一个树,让你求树的直径. 分析: 树的直径:树上两点之间的最大距离. 我们从任意一点出发,BFS一个最远距离,然后从这个点出发,在BFS一个最远距离,就是树的直径. AC代码: /* POJ:1985 Cow Marathon 2014/10/12/21:18 Yougth*/ #include <cstdio> #include <iostream> #include <algorithm> #include

poj1849(求树的直径)

题目链接:http://poj.org/problem?id=1849 题意:有一颗n个结点的带权的无向树, 在s结点放两个机器人, 这两个机器人会把树的每条边都走一遍, 但是最后机器人不要求回到出发点. 问你两个机器人走的路总长之和的最小值是多少? 分析:如果从某点出发遍历完一棵树再回来,那么所有边都会走两遍,而从某点有两个机器人出发去遍历,因为不用回来,所以最后那两个人距离越远越好,可以从树的直径上某个点背道而驰,那么这段距离(树的直径)只走了一遍,其他的要走两遍,所以ans=sum*2-l