bzoj1791: [Ioi2008]Island 岛屿 基环树

bzoj1791: [Ioi2008]Island 岛屿

Description

你将要游览一个有N个岛屿的公园。从每一个岛i出发,只建造一座桥。桥的长度以Li表示。公园内总共有N座桥。尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走。同时,每一对这样的岛屿,都有一艘专用的往来两岛之间的渡船。 相对于乘船而言,你更喜欢步行。你希望所经过的桥的总长度尽可能的长,但受到以下的限制。 • 可以自行挑选一个岛开始游览。 • 任何一个岛都不能游览一次以上。 • 无论任何时间你都可以由你现在所在的岛S去另一个你从未到过的岛D。由S到D可以有以下方法: o 步行:仅当两个岛之间有一座桥时才有可能。对于这种情况,桥的长度会累加到你步行的总距离;或者 o 渡船:你可以选择这种方法,仅当没有任何桥和/或以前使用过的渡船的组合可以由S走到D(当检查是否可到达时,你应该考虑所有的路径,包括经过你曾游览过的那些岛)。 注意,你不必游览所有的岛,也可能无法走完所有的桥。 任务 编写一个程序,给定N座桥以及它们的长度,按照上述的规则,计算你可以走过的桥的最大长度。 限制 2 <= N <= 1,000,000 公园内的岛屿数目。 1<= Li <= 100,000,000 桥i的长度。

Input

• 第一行包含N个整数,即公园内岛屿的数目。岛屿由1到N编号。 • 随后的N行每一行用来表示一个岛。第i 行由两个以单空格分隔的整数,表示由岛i筑的桥。第一个整数表示桥另一端的岛,第二个整数表示该桥的长度Li。你可以假设对於每座桥,其端点总是位于不同的岛上。

Output

你的程序必须向标准输出写出包含一个整数的单一行,即可能的最大步行距离。 注1:对某些测试,答案可能无法放进32-bit整数,你要取得这道题的满分,可能需要用Pascal的int64或C/C++的long long类型。 注2:在比赛环境运行Pascal程序,由标准输入读入64-bit数据比32-bit数据要慢得多,即使被读取的数据可以32-bit表示。我们建议把输入数据读入到32-bit数据类型。 评分 N不会超过4,000。

Sample Input

7
3 8
7 2
4 2
1 4
1 9
3 4
2 3

Sample Output

24
HINT
这里写图片描述

分析

一句话题意:基环树森林的各个树直径。
直径只可能再外向树中或者是环+若干外向树到根最长链 d i
再环上搞前缀和 s i ,设环长是 s u m ,则答案就是
a n s = m a x ( m a x ( s i s j , s u m ( s i s j ) ) + d i + d j )
一个比较巧妙的处理方法是
a n s = m a x ( m a x ( s i + d i ( s j d j ) , s u m s i + d i + ( s j + d j ) ) ) )
固定i,那么 s i + d i , s u m s i + d i 是定值。
只要维护 s j d j 的前缀最小值和 s j + d j 的前缀最大值即可。

代码

#include<cstdio>
#include<algorithm>
using std::max; using std::min;
const int N = 2e6 + 10;
int ri() {
    char ch = getchar(); int x = 0;
    for(;ch < '0' || ch > '9'; ch = getchar()) ;
    for(;ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) - '0' + ch;
    return x;
}
int to[N], nx[N], w[N], pr[N], f[N], L[N], st[N], tp, x, n;
bool vis[N], c[N];
long long D, d[N], a[N], sum, ans;
void add(int u, int v, int ww) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp; w[tp] = ww;}
void adds(int u, int v, int w) {add(u, v, w); add(v, u, w);}
void Dfs(int u, int f, long long v) {
    vis[u] = true; if(v > D) {D = v; x = u;}
    for(int i = pr[u]; i; i = nx[i]) if(to[i] != f && !c[to[i]]) Dfs(to[i], u, v + w[i]);
}
int main() {
    n = ri(); for(int i = 1;i <= n; ++i) f[i] = ri(), L[i] = ri(), adds(f[i], i, L[i]);
    for(int i = 1, tp, k;i <= n; ++i)
    if(!vis[i]) {
        for(k = i; !vis[k]; k = f[k]) vis[k] = true; long long cr = 0;
        for(c[st[tp = 1] = k] = true; (k = f[k]) != st[1]; ) c[st[++tp] = k] = true;
        for(int j = 1;j <= tp; ++j) { 
            x = D = 0; Dfs(st[j], 0, 0); d[j] = D; if(x) c[st[j]] = false, Dfs(x, 0, 0), c[st[j]] = true;
            cr = max(cr, D); a[j] = a[j - 1] + L[st[j - 1]];
        } sum = a[tp] + L[st[tp]];
        long long mx = -1e18, mn = 1e18;
        for(int j = 1;j <= tp; ++j) {
            cr = max(cr, max(a[j] + d[j] - mn, sum - (a[j] - d[j]) + mx));
            mx = max(mx, a[j] + d[j]); mn = min(mn, a[j] - d[j]);
        } 
        ans += cr;
    }
    printf("%lld\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/80647506
今日推荐