1791: [Ioi2008]Island 岛屿

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 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

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 = ;
struct edge {
int nxt, w, to;
} e[N << ];
vector<int> route;
int n, cnt = , pos;
ll ans, Max;
int used[N], vis[N], head[N], mark[N], w[N], prev[N], pree[N << ];
ll mx[N], d[N << ], g[N], q[N], dp[N];
inline int read()
{
int x = , f = ; char c = getchar();
while(c < '' || c > '') { if(c == '-') f = -; c = getchar(); }
while(c >= '' && c <= '') { x *= ; x += c - ''; 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 = , Max2 = ;
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] = ; 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] = ;
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, );
for(int now = pos; !mark[now]; now = prev[now])
{
mark[now] = ;
route.push_back(now); w[now] = e[pree[now]].w;
}
for(int i = ; i < route.size(); ++i)
{
ll Max1 = , Max2 = ;
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 = ;
}
}
int lim = route.size(), l = , r = ;
for(int i = ; i < lim; ++i) route.push_back(route[i]);
d[] = q[l] = ;
for(int i = ; i < route.size(); ++i) d[i + ] = d[i] + w[route[i]];
ll delta = mx[route[]] + d[];
for(int i = ; i < route.size(); ++i)
{
while(q[r] - q[l] + >= 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\n" :: "r"(p));
freopen("isl.in", "r", stdin);
freopen("isl.out", "w", stdout);
n = read();
for(int i = ; i <= n; ++i)
{
int u, w; u = read(); w = read();
link(i, u, w); link(u, i, w);
}
for(int i = ; i <= n; ++i) if(!used[i]) solve(i);
printf("%lld\n", ans);
fclose(stdin); fclose(stdout);
return ;
}

bzoj1791的更多相关文章

  1. 【bzoj1791】岛屿

    [bzoj1791]岛屿 题意 求基环树的直径. \(n\leq 100000\) 分析 这道题的题解貌似很少啊. 所以自己也写一份吧. 首先找出基环树的环. 那么树的直径有两种情况: ①以环为根的某 ...

  2. [BZOJ1791][IOI2008]Island岛屿(环套树DP)

    同NOI2013快餐店(NOI出原题?),下面代码由于BZOJ栈空间过小会RE. 大致是对每个连通块找到环,在所有内向树做一遍DP,再在环上做两遍前缀和优化的DP. #include<cstdi ...

  3. BZOJ1791: [Ioi2008]Island 岛屿

    BZOJ1791: [Ioi2008]Island 岛屿 Description 你将要游览一个有N个岛屿的公园. 从每一个岛i出发,只建造一座桥. 桥的长度以Li表示. 公园内总共有N座桥. 尽管每 ...

  4. BZOJ1791 基环树直径

    非递归版4S /************************************************************** Problem: 1791 User: 18357 Lan ...

  5. [IOI2008/BZOJ1791 岛屿](处理基环树的小技巧&基于bfs树形DP)

    IOI2008/BZOJ1791 岛屿 题目大意是在一个基环树森林里求每一棵基环树的直径①的和. 其实就是树的直径的基环树升级版.我们先把环找出来,然后从环上的每一个节点x出发,并且不经过环上其他节点 ...

  6. [bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)

    [bzoj1791][ioi2008]Island 岛屿(基环树.树的直径) bzoj luogu 题意可能会很绕 一句话:基环树的直径. 求直径: 对于环上每一个点记录其向它的子树最长路径为$dp_ ...

  7. 【BZOJ1791】【IOI2008】【基环树】island(status第一速度)

      1791: [Ioi2008]Island 岛屿  Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 908  Solved: 159 [Su ...

  8. bzoj1791: [Ioi2008]Island 岛屿 单调队列优化dp

    1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1826  Solved: 405[Submit][S ...

  9. bzoj1791[IOI2008]Island岛屿(基环树+DP)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1791 题目大意:给你一棵n条边的基环树森林,要你求出所有基环树/树的直径之和.n< ...

  10. BZOJ1791[Ioi2008]Island 岛屿 ——基环森林直径和+单调队列优化DP+树形DP

    题目描述 你将要游览一个有N个岛屿的公园.从每一个岛i出发,只建造一座桥.桥的长度以Li表示.公园内总共有N座桥.尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走.同时,每一对这样的岛屿,都有一 ...

随机推荐

  1. 笔记——python风格规范

    分号 不要在行尾加分号, 也不要用分号将两条命令放在同一行. 行长度 每行不超过80个字符 例外: 长的导入模块语句 注释里的URL 不要使用反斜杠连接行. Python会将 圆括号, 中括号和花括号 ...

  2. 九度oj 题目1206:字符串连接

    题目1206:字符串连接 时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:5117 解决:2373 题目描述: 不借用任何字符串库函数实现无冗余地接受两个字符串,然后把它们无冗余的连接起来 ...

  3. [USACO12FEB]附近的牛Nearby Cows

    题目描述 Farmer John has noticed that his cows often move between nearby fields. Taking this into accoun ...

  4. codevs4439 YJQ Requires Food

    题目描述 Description 神犇YJQ有n个不同的妹子和m种食物,每一天每一种食物只供应一个妹子吃的份量.在接下来的t天内,YJQ准备包养所有的妹子. 对于每个妹子,她在t天内都只会吃某些特定的 ...

  5. UVA 140_Bandwidth

    题意: 定义一个结点的带宽是其距离所有相连结点的最远距离,一个图的带宽是图中所有结点带宽的最小值.给出一个图中各个结点的相邻情况,要求写出一个结点的排列,使得其所构成的图带宽最小. 分析: 枚举全排列 ...

  6. Sum-(最大子序列和)

    http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=652&pid=1003 题目大意: 给你一个序列,你随便找一 ...

  7. 解析excel文件并将数据导入到数据库中

    今天领导给安排了一个临时工作,让我将一个excel里面的数据解析后放入数据库中,经过一个下午的努力成功完成,现在将代码献上,希望对大家有所帮助 一.需要导入的jar 1.commons-collect ...

  8. cogs 48. [NOIP2007] 字符串的展开

    48. [NOIP2007] 字符串的展开 ★☆   输入文件:expand.in   输出文件:expand.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 在初赛普 ...

  9. Ubuntu 16.04安装ntopng流量监控软件

    ntop官方在2012年就已经不再更新,取代的是ntopng.ntopng具有Web页面,适合做网络管理监控软件.比如监控局域网内多台机器的上网情况等. 不过这个东西感觉不太准,最好的方案应该把安装n ...

  10. linux man 1,2,3 命令

    原文: http://blog.sina.com.cn/s/blog_969c52730101c0p7.html ------------------------------------------- ...