BZOJ 1999 [Noip2007]Core树网的核 樹的直徑

$ \rightarrow $ 戳我進BZOJ原題 $ \rightarrow $ 戳我進洛谷原題

树网的核

时空限制 1000ms / 64MB

题目描述

设 $ 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 $ 上的结点。
 
树网的直径:树网中最长的路径成为树网的直径。对于给定的树网 $ T $,直径不一定是唯一的,
但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。
 
偏心距 $ ECC(F) $ :树网T中距路径F最远的结点到路径 $ F $ 的距离,即
 
$ ECC(F)=max $ { $ d(v,F),v∈V $ }
 
任务:对于给定的树网 $ T=(V,E,W) $ 和非负整数 $ s $ ,求一个路径 $ F $ ,
他是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过 $ s $ (可以等于 $ s $ ),使偏心距 $ ECC(F) $ 最小。
我们称这个路径为树网 $ T=(V,E,W) $ 的核(Core)。
必要时,$ F $ 可以退化为某个结点。
一般来说,在上述定义下,核不一定只有一个,但最小偏心距是唯一的。
 
下面的图给出了树网的一个实例。
图中,$ A−B $ 与 $ A−C $ 是两条直径,长度均为 $ 20 $ 。
点 $ W $ 是树网的中心,$ EF $ 边的长度为 $ 5 $ 。
如果指定 $ s=11 $ ,则树网的核为路径 $ DEFG $(也可以取为路径 $ DEF $ ),偏心距为 $ 8 $ 。
如果指定 $ s=0 $ (或 $ s=1、s=2 $ ),则树网的核为结点 $ F $ ,偏心距为 $ 12 $ 。

pic1

输入输出格式

输入格式

共 $ n $ 行。
 
第 $ 1 $ 行,两个正整数 $ n $ 和 $ s $ ,中间用一个空格隔开。
其中 $ n $ 为树网结点的个数,$ s $ 为树网的核的长度的上界。设结点编号以此为 $ 1,2,…,n $ 。
 
从第 $ 2 $ 行到第 $ n $ 行,每行给出 $ 3 $ 个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。
例如,“ $ 2 \quad 4 \quad 7 $ ”表示连接结点 $ 2 $ 与 $ 4 $ 的边的长度为 $ 7 $ 。
 

输出格式

一个非负整数,为指定意义下的最小偏心距。
 

输入输出样例

输入样例#1

 5 2
 1 2 5
 2 3 2
 2 4 4
 2 5 3

输出样例#1

 5

输入样例#2

 8 6
 1 3 2
 2 3 2 
 3 4 6
 4 5 3
 4 6 4
 4 7 2
 7 8 3

输出样例#2

 5

 

说明

$ 40 $ %的数据满足:$ 5≤n≤15 $

$ 70 $ %的数据满足:$ 5≤n≤80 $

$ 100 $ %的数据满足:$ 5≤n≤300,0≤s≤1000 $ 。边长度为不超过 $ 1000 $ 的正整数

NOIP 2007 提高第四题

 

HINT

(BZOJ的数据)

对于 $ 70 $ %的数据,$ n \le 200000 $
对于 $ 100 $ %的数据:$ n \le 500000, s<2^{31} $ , 所有权值 $ <500 $

 

題解

  • 樹的直徑不唯一,但所有直徑必定相交,并且各直徑的中點匯聚于同一處。

  • 進一步可以得到一個推論:在任意一條直徑上求出的最小偏心距都相等。

  • 於是,我們首先任意找到一條直徑。

 

  • 解法一:枚舉 $ O(n^3) $
    在直徑上枚舉距離不超過 $ s $ 的兩個點 $ p $ 和 $ q $ 作爲“核”, $ DFS $ 求偏心距

 

  • 解法二:枚舉+貪心 $ O(n^2) $
    根據貪心策略,在 $ p $ 固定后,另一端 $ q $ 在距離不超過 $ s $ 的前提下,顯然越遠越好。
    所以只需要枚舉 $ p $ ,不用枚舉 $ q $

 

  • 解法三:二分答案 $ O(n log SUM) $

  • 本題的答案具有單調性,可以二分答案,把問題轉化爲:

  • “驗證是否存在一個核,其偏心距不超過二分的值 $ mid $ ” 。

 

  • 在直徑上找到:距離不超過 $ mid $ 的前提下,離兩端最遠的節點,分別作爲節點 $ p, q $ 。

  • 根據直徑的最長性,只需檢查 $ p, q $ 之間的路徑能否構成滿足條件的”核“

 

  • 解法四:分析性質,直接掃描 $ O(n) $

  • 設直徑上的節點為 $ u_1,u_2, \dots ,u_t $

  • $ DFS $ 求出 $ d[u_i] $ ,表示從 $ u_i $ 出發,不經過直徑上的其他節點,能夠到達的最遠點的距離

  • 以 $ u_i, u_j ( i \le j ) $ 為端點的樹網的核的偏心距就是

  • $ max(max_{i \le k \le j}d[u_k], \quad dist(u_1,u_i), \quad dist(u_j,u_t) = max(max_{1 \le k \le t}d[u_k], \quad ,dist(u_1,u_i), \quad dist(u_j,u_t)) $
     

  • $ max_{1 \le k \le t }d[u_k] $ 對於 $ u_i , u_j $ 來説是一個定值

  • 只需要枚舉直徑上的每個點 $ u_i $ ,用一個指針單調向後移動,即可得到 $ u_j $ 並更新答案
     

代碼

/**************************************************************
    Problem: 1999
    User: PotremZ
    Language: C++
    Result: Accepted
    Time:2580 ms
    Memory:39768 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 500010
struct edge{ int v,w; };
vector<edge>e[maxn];
int n,s,dis[maxn],f[maxn],d,ans=1e9+7;
bool vis[maxn];
void add(int u,int v,int w){ e[u].push_back((edge){v,w}); }
void dfs(int u,int fa){
    f[u]=fa; 
    for(int i=0;i<e[u].size();++i)
        if(!vis[e[u][i].v]&&e[u][i].v!=fa){
            dis[e[u][i].v]=dis[u]+e[u][i].w;
            dfs(e[u][i].v,u);
        }
}
int main(){
    scanf("%d %d",&n,&s);
    for(int u,v,w,i=1;i<n;++i){
        scanf("%d %d %d",&u,&v,&w);
        add(u,v,w); add(v,u,w);
    }
    dfs(1,0); for(int i=1;i<=n;++i) if(dis[i]>dis[d]) d=i;
    dis[d]=0; dfs(d,0); for(int i=1;i<=n;++i) if(dis[i]>dis[d]) d=i;
    int j=d;
    for(int i=d;i;i=f[i]){
        while(f[j]&&dis[i]-dis[f[j]]<=s) j=f[j];
        ans=min(ans,max(dis[j],dis[d]-dis[i]));
    }
    for(int i=d;i;i=f[i]){ vis[i]=1; dis[i]=0; dfs(i,f[i]); }
    for(int i=1;i<=n;++i) ans=max(ans,dis[i]);
    printf("%d",ans);
    return 0;
}
posted @ 2018-09-06 22:07  potrem  阅读(220)  评论(0编辑  收藏  举报