bzoj 1999 分类: bzoj noip 2015-08-07 23:37 15人阅读 评论(0) 收藏


树网的核 加强版,好题~


可以证明,如果存在多条直径,选取任意一条直径都是等价的。


证明:

如图,考虑两条直径 AB, CD,其中它们的重合部分为 EF

 A                           B
  \                         /                         
   \                       /
    \_____________________/
    /E                   F\
   /                       \
  /                         \
 C                           D

先证 |AE| = |CE|, |BF| = |DF|

|AE| +|EF| + |BF| = |CE| + |EF| + |DF| |AE| + |BF| = |CE| + |DF|

若|AE| > |CE|, 则 |BF| < |DF|,那么 |AD| >|AB|
而AB为树的直径,推出矛盾,所以 |AE| <= |CE|

同理可证 |AE| >= |CE|,|BF| <= |DF|,|BF| >= |DF|

|AE| = |CE|, |BF| = |DF|


现在证明,在任意一条直径上选取路径 p 计算偏心距是等价的。

如果 p 没有覆盖 EF,其它直径上的点对偏心距没有贡献。

如果 p 覆盖 EF。

  • p 在AB上时,CD上的点对偏心距的贡献为 |CE| 和 |DF|
  • p 在CD上时,AB上的点对偏心距的贡献为 |AE| 和 |BF|

|AE| = |CE|, |BF| = |DF|
在任意一条直径上选取路径 p 计算偏心距是等价的

综上所述,结论成立。


根据贪心的原则,在直径上选取尽量长的路径 p 可以使得偏心距最小。

对于这条路径,如何计算偏心距?

记直径左端点为 L, 右端点为 R,这条路径左端点为 l,右端点为 r

ECC(p) = max{max{g(i) | i p },dist(L, l) , dist(r, R)}

其中 g(i) 表示 i 点不经过直径能到达的最远距离。

对于 max{g(i) | i p },用单调队列维护 g(i) | i p 下降即可。

时间复杂度:O(n)


/**************************************************************
    Problem: 1999
    User: cyxhahaha
    Language: C++
    Result: Accepted
    Time:1496 ms
    Memory:58324 kb
****************************************************************/

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <string>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <utility>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
    return;
}
template<class Num>void write(Num x)
{
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    if(!sl) {putchar('0');return;}
    while(sl) putchar(s[--sl]);
}

#define REP(__x,__st,__ed) for(int __x = (__st); __x <= (__ed); __x++)

const int maxn = 5e5 + 5, Nya = -1;

int n, S;

struct Edge
{
    int v, w, next;

    Edge(int v=0,int w=0,int next=0):v(v),w(w),next(next){}

}edge[maxn<<1];

int el, head[maxn];

int dist[maxn], path[maxn], len;
int Lmax[maxn], Rmax[maxn], Mmax[maxn];
bool hash[maxn];

void NewEdge(int u,int v,int w)
{
    edge[++el] = Edge(v, w, head[u]), head[u] = el;
}

void dfs(int a,int fa,int arr[])
{
    for(int i = head[a]; i; i = edge[i].next)
    {
        int p = edge[i].v;

        if(p == fa) continue;

        arr[p] = arr[a] + edge[i].w;

        dfs(p, a, arr);
    }
}

int gainmax(int a,int fa)
{
    int ret = 0;

    for(int i = head[a]; i ; i = edge[i].next)
    {
        int p = edge[i].v;

        if(p == fa || hash[p]) continue;

        ret = std::max(gainmax(p, a) + edge[i].w, ret);
    }
    return ret;
}

bool find(int a,int aim,int fa)
{
    if(a == aim)
    {
        path[++len] = a;
        return true;
    }
    for(int i = head[a]; i; i = edge[i].next)
    {
        if(edge[i].v == fa) continue;

        if(find(edge[i].v, aim, a))
        {
            path[++len] = a;
            return true;
        }
    }
    return false;
}
void init()
{
    int u, v, w;

    read(n), read(S);
    for(int i = 1; i < n; i++)
    {
        read(u), read(v), read(w);
        NewEdge(u, v, w);
        NewEdge(v, u, w);
    }
}
void diameter()
{
    int s = 1, t = 1;

    dist[1] = 0, dfs(1, 0, dist);

    REP(i, 1, n)
        if(dist[i] > dist[s])
            s = i;

    dist[s] = 0, dfs(s, 0, dist);

    REP(i, 1, n)
        if(dist[i] > dist[t])
            t = i;

    find(t, s, 0);              

    REP(i, 1, len) hash[path[i]] = true;

    REP(i, 1, len) Mmax[i] = gainmax(path[i], 0);

    REP(i, 1, len)
    {
        Lmax[i] = dist[path[i]] - dist[path[1]];
        Rmax[i] = dist[path[len]] - dist[path[i]];
    }
}
void solve()
{
    static int line[maxn];
    int f = 0, r = 0, ans = Nya, cal;

    for(int i = 1, j = 1; i <= len; i++)
    {
        if(f != r && line[f] < i) line[f++] = 0;

        while(j <= n && dist[path[j]] - dist[path[i]] <= S)
        {
            while(f != r && Mmax[line[r-1]] <= Mmax[j]) line[--r] = 0;
            line[r++] = j++;
        }

        cal = std::max(Mmax[line[f]], std::max(Lmax[i], Rmax[j-1]));

        if(ans == Nya || cal < ans) ans = cal;

    }

    write(ans);
}

int main()
{
#ifndef ONLINE_JUDGE    
    freopen("1999.in","r",stdin);
    freopen("1999.out","w",stdout);
#endif

    init(), diameter(), solve();

#ifndef ONLINE_JUDGE    
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;   
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2015-08-07 23:37  <Dash>  阅读(159)  评论(0编辑  收藏  举报