1. 程式人生 > >BZOJ1999 NOIP2007 洛谷P1099 P2491 SDOI 2011

BZOJ1999 NOIP2007 洛谷P1099 P2491 SDOI 2011

一般來說 scan ges ons isp clu script ebe post

Description:

設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。

(圖好像咕咕咕了)

Input:

輸入文件core.in包含n行:

第1行,兩個正整數n和s,中間用一個空格隔開。其中n為樹網結點的個數,s為樹網的核的長度的上界。設結點編號以此為1,2,……,n。

從第2行到第n行,每行給出3個用空格隔開的正整數,依次表示每一條邊的兩個端點編號和長度。例如,“2 4 7”表示連接結點2與4的邊的長度為7。

Output:

輸出文件core.out只有一個非負整數,為指定意義下的最小偏心距。

思路:

找到最長鏈後暴力枚舉可以過掉NOIP的測試數據,但這個算法太鹹魚了 我們顯然不能這麽鹹魚下去對不對?

考慮貪心,找到直徑後枚舉一個起點,然後終點明顯越遠越好可以直接確定,然後從每個節點出發求偏心距,復雜度N2

也可以對偏心距進行二分枚舉答案然後求直徑上的核,復雜度NlogN

但復雜度可以到On

預處理出從直徑上的每個節點出發,能到達最遠點的距離d,並用前綴和預處理出直徑上兩兩點間的距離

那麽拿一個長度為s的滑動窗口掃一遍直徑求出最小值就行了

沒了

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
const int N = 300010;

int head[N], now = 1;
struct edges{
    int to, next, w;
}edge[N<<1];
void add(int u, int v, int w){ edge[++now] = {v, head[u], w}; head[u] = now;}

int n, lim, dep[N], d[N], pre[N], pos1, pos2;
bool isd[N];
int mymax(int x,int y,int z){
    return max(x, y) > z ? max(x, y):z;
}
void dfs1(int x,int fa){
    for(int i = head[x]; i; i = edge[i].next){
        int v = edge[i].to;
        if(v == fa) continue;
        dep[v] = dep[x] + edge[i].w;
        dfs1(v, x);
    }
    if(dep[x] > dep[pos1])
      pos1 = x;
}
void dfs2(int x,int fa){
    for(int i = head[x]; i; i = edge[i].next){
        int v = edge[i].to;
        if(v == fa) continue;
        d[v] = d[x] + edge[i].w;
        pre[v] = i;
        dfs2(v, x); 
    }
    if(d[x] > d[pos2])
      pos2 = x;
}
int dis[N];
void dfs(int x, int fa){
    for(int i = head[x]; i; i = edge[i].next){
        int v = edge[i].to;
        if(v == fa || isd[v]) continue;
        dfs(v, x);
        dis[x] = max(dis[x], dis[v] + edge[i].w);
    }
}
int a[N], tot;
int main(){
    scanf("%d%d",&n, &lim);
    int x, y, z;
    for(int i = 1; i < n; i++){
        scanf("%d%d%d",&x, &y, &z);
        add(x, y, z); add(y, x, z);
    }
    dfs1(1, -1);
    dfs2(pos1, -1);
//    cout<<pos1<<" "<<pos2<<endl;
    for(int i = pos2; i; i = edge[pre[i] ^ 1].to)
      isd[i] = 1 ,a[++tot] = i;
    int ans = 1e9, mx = 0;
    for(int i = 1; i <= tot; i++){
        dfs(a[i], -1);
        mx = max(mx, dis[a[i]]);
    }
    int i = 1;
    for(int j = i; j <= tot; j++){
        while(d[a[i]] - d[a[j]] > lim)
          i++;
        int tmp = mymax(mx, d[a[1]] - d[a[i]], d[a[j]] - d[a[tot]]);
        ans = min(ans, tmp);
    }
    printf("%d\n",ans);
    return 0;
}
View Code

BZOJ1999 NOIP2007 洛谷P1099 P2491 SDOI 2011