1791: [Ioi2008]Island 岛屿
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1680 Solved: 369
[Submit][Status][Discuss]
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
3 8
7 2
4 2
1 4
1 9
3 4
2 3
Sample Output
24
HINT
Source
这个图跟信息传递很像,也就是一个基环树,但是我很思博地没看出来。。。
事实上这是一个基环树森林,我们要求的是每棵基环树的直径(不太准确),也就是基环树上最长的路径
首先得找到环,这里我们可以分两种情况
1.这条路径在环上,那么也就是说两个端点在环上某个顶点的子树里或环上,那么这个样子可以这么计算:dis=d子树1+d子树2+d环,我们先把环拉开复制一遍接在后面,然后对于环上每个顶点的子树计算一下子树最深的地方到环上该点的距离,这些子树取个最大值。然后就可以dp了dp[i] = max(dp[i], d[i]-d[j]) 这里可以用单调队列优化,具体看代码
2.最长路径位于环上某个顶点的子树里,或者跨越某个顶点的两颗子树。这里就是一个树形dp,代码里写的不清楚,其实就是求树的直径的代码。
吐槽:写了4个小时,忽略了好几种情况,竟然还会爆栈,我不会写手工栈。。。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1000010; struct edge { int nxt, w, to; } e[N << 1]; vector<int> route; int n, cnt = 1, pos; ll ans, Max; int used[N], vis[N], head[N], mark[N], w[N], prev[N], pree[N << 1]; ll mx[N], d[N << 1], g[N], q[N], dp[N]; inline int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x *= 10; x += c - '0'; c = getchar(); } return x * f; } inline void link(int u, int v, int w) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].to = v; e[cnt].w = w; } void Dp(int u, int last) { ll Max1 = 0, Max2 = 0; for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last) { Dp(e[i].to, u); if(g[e[i].to] + (ll)e[i].w >= Max1) { Max2 = Max1; Max1 = g[e[i].to] + (ll)e[i].w; } else if(g[e[i].to] + (ll)e[i].w > Max2) Max2 = g[e[i].to] + (ll)e[i].w; Max = max(Max, Max1 + Max2); } g[u] = Max1; } bool getcir(int u, int last) { vis[u] = 1; bool flag = false; for(int i = head[u]; i; i = e[i].nxt) { if(e[i].to == last && !flag) { flag = true; continue; } if(!vis[e[i].to]) { prev[e[i].to] = u; pree[e[i].to] = i; if(getcir(e[i].to, u)) return true; } else { pree[e[i].to] = i; pos = u; prev[e[i].to] = u; return true; } } return false; } void dfs(int u) { used[u] = 1; for(int i = head[u]; i; i = e[i].nxt) if(!used[e[i].to]) dfs(e[i].to); } void solve(int u) { route.clear(); getcir(u, 0); for(int now = pos; !mark[now]; now = prev[now]) { mark[now] = 1; route.push_back(now); w[now] = e[pree[now]].w; } for(int i = 0; i < route.size(); ++i) { ll Max1 = 0, Max2 = 0; for(int j = head[route[i]]; j; j = e[j].nxt) if(!mark[e[j].to]) { Dp(e[j].to, route[i]); if(g[e[j].to] + (ll)e[j].w >= Max1) { Max2 = Max1; Max1 = g[e[j].to] + e[j].w; } else if(g[e[j].to] + e[j].w > Max2) Max2 = g[e[j].to] + e[j].w; mx[route[i]] = max(mx[route[i]], g[e[j].to] + (ll)e[j].w); dp[route[i]] = max(dp[route[i]], max(Max, Max1 + Max2)); Max = 0; } } int lim = route.size(), l = 0, r = 0; for(int i = 0; i < lim; ++i) route.push_back(route[i]); d[0] = q[l] = 0; for(int i = 0; i < route.size(); ++i) d[i + 1] = d[i] + w[route[i]]; ll delta = mx[route[0]] + d[0]; for(int i = 0; i < route.size(); ++i) { while(q[r] - q[l] + 1 >= lim && l <= r) ++l; if(i) delta = max(delta, mx[route[i]] + d[i] + mx[route[q[l]]] - d[q[l]]); delta = max(delta, dp[route[i]]); ll x = mx[route[i]] - d[i]; while(l <= r) if(x > mx[route[q[r]]] - d[q[r]]) --r; else break; q[++r] = i; } ans += delta; dfs(u); } int main() { // int size = 50 << 20; // 256MB // char *p = (char*)malloc(size) + size; // __asm__("movl %0, %%esp " :: "r"(p)); freopen("isl.in", "r", stdin); freopen("isl.out", "w", stdout); n = read(); for(int i = 1; i <= n; ++i) { int u, w; u = read(); w = read(); link(i, u, w); link(u, i, w); } for(int i = 1; i <= n; ++i) if(!used[i]) solve(i); printf("%lld ", ans); fclose(stdin); fclose(stdout); return 0; }