目录

P4381-[IOI2008]Island

P4381-[IOI2008]Island

题目:

题目描述:

你准备浏览一个公园,该公园由 $N$ 个岛屿组成,当地管理部门从每个岛屿 $i$ 出发向另外一个岛屿建了一座长度为 $L_i$ 的桥,不过桥是可以双向行走的。同时,每对岛屿之间都有一艘专用的往来两岛之间的渡船。相对于乘船而言,你更喜欢步行。你希望经过的桥的总长度尽可能长,但受到以下的限制:

  • 可以自行挑选一个岛开始游览。
  • 任何一个岛都不能游览一次以上。
  • 无论任何时间,你都可以由当前所在的岛 $S$ 去另一个从未到过的岛 $D$。从 $S$ 到 $D$ 有如下方法:
    • 步行:仅当两个岛之间有一座桥时才有可能。对于这种情况,桥的长度会累加到你步行的总距离中。
    • 渡船:你可以选择这种方法,仅当没有任何桥和以前使用过的渡船的组合可以由 $S$ 走到 $D$ (当检查是否可到达时,你应该考虑所有的路径,包括经过你曾游览过的那些岛)。

注意,你不必游览所有的岛,也可能无法走完所有的桥。

请你编写一个程序,给定 $N$ 座桥以及它们的长度,按照上述的规则,计算你可以走过的桥的长度之和的最大值。

输入格式:

第一行包含 $N$ 个整数,即公园内岛屿的数目。

随后的 $N$ 行每一行用来表示一个岛。第 $i$ 行由两个以单空格分隔的整数,表示由岛 $i$ 筑的桥。第一个整数表示桥另一端的岛,第二个整数表示该桥的长度 $L_i$。你可以假设对于每座桥,其端点总是位于不同的岛上。

输出格式:

仅包含一个整数,即可能的最大步行距离。

样例:

样例输入1:

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

样例输出1:

1
24

思路:

实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "ybwhead/ios.h"
int n;
const int maxn = 1e6 + 10;
struct edge
{
    int v, w, nxt;
} e[maxn << 1];
int tot, head[maxn];
void __ADD(int u, int v, int w)
{
    e[++tot] = {v, w, head[u]};
    head[u] = tot;
}
void add(int u, int v, int w)
{
    __ADD(u, v, w);
    __ADD(v, u, w);
}
bool v[maxn];
int v1[maxn];
long long ans;
int now, cnt;
int r[maxn];
int st;
long long s[maxn];
int dfs1(int u, int fa)
{
    if (v1[u] == 1)
    {
        v1[u] = 2;
        r[++cnt] = u;
        v[u] = 1;
        return 1;
    }
    v1[u] = 1;
    // cout << u << endl;
    for (int i = head[u]; i; i = e[i].nxt)
    {
        int vv = e[i].v;
        if (i == ((fa - 1) ^ 1) + 1)
            continue;
        int tt = dfs1(vv, i);
        if (tt == 0)
            continue;
        if (v1[u] == 2)
        {
            s[st - 1] = s[st] - e[i].w;
            return 0;
        }
        r[++cnt] = u;
        v[u] = 1;
        s[cnt] = s[cnt - 1] + e[i].w;
        return 1;
    }
    return 0;
}
long long ans1, ans2, ans3;
long long d[maxn];
void dp(int u)
{
    v[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt)
    {
        int vv = e[i].v;
        if (v[vv])
            continue;
        dp(vv);
        ans1 = max(ans1, d[u] + d[vv] + e[i].w);
        d[u] = max(d[u], d[vv] + e[i].w);
    }
}
long long f[maxn << 1];
deque<int> q;
long long dfs(int u)
{
    st = cnt + 1;
    ans2 = ans3 = 0;
    dfs1(u, 0);
    for (int i = st; i <= cnt; i++)
    {
        ans1 = 0;
        dp(r[i]);
        ans2 = max(ans2, ans1);
        f[i + cnt - st + 1] = f[i] = d[r[i]];
        s[i + cnt - st + 1] = s[i + cnt - st] + s[i] - s[i - 1];
        // yout << i << " " << s[4] << " " << s[3] << endl;
    }
    while (!q.empty())
        q.pop_back();
    // puts("!!!");
    for (int i = st; i <= cnt * 2 - st + 1; i++)
    {
        while (!q.empty() && q.front() <= i - cnt + st - 1)
            q.pop_front();
        // yout << q.front() << " " << i - cnt + st - 1 << endl;
        if (!q.empty())
            ans3 = max(ans3, f[i] + f[q.front()] + s[i] - s[q.front()]);
        while (!q.empty() && f[q.back()] - s[q.back()] <= f[i] - s[i])
            q.pop_back();
        q.push_back(i);
        // yout << ans3 << endl;
    }
    return max(ans2, ans3);
}
int main()
{
    yin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x, y;
        yin >> x >> y;
        add(i, x, y);
    }
    for (int i = 1; i <= n; i++)
        if (!v[i])
            ans += dfs(i);
    yout << ans << endl;
    return 0;
}