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之面向对象多态

    Python之面向对象多态 多态与多态性: 多态: 多态是指一类事物有多种形态,一个抽象类有多个子类,因而多态的概念依赖于继承. 1.序列类型有多种形态:字符串.列表.元组. 2.动物有多种形态:Pe ...

  2. CSU1160

    十进制-十六进制 Time Limit: 1 Sec  Memory Limit: 128 MB Description 把十进制整数转换为十六进制,格式为0x开头,10~15由大写字母A~F表示. ...

  3. UvaLive 4863 Balloons(贪心)

    题意: 给定n个队伍, 然后A房间有a个气球, B房间有b个气球, 然后给出每个队伍所需要的气球数量和到A B房间的距离, 求把气球全部送到每个队伍的最短距离. 分析: 在气球充足的情况下, 那么我们 ...

  4. codeforces 330b

    #include<stdio.h> #include<string.h> #include<stdlib.h> #define N 1100 int map[N]; ...

  5. [转]MySQL5字符集支持及编码研究

    前言 在更新数据库时,有时会遇到这样的错误: Illegal mix of collations (gbk_chinese_ci,IMPLICIT) and (utf8_general_ci,COER ...

  6. Codeforces 645C Enduring Exodus【二分】

    题目链接: http://codeforces.com/contest/645/problem/C 题意: 给定01串,将k头牛和农夫放进, 0表示可以放进,1表示不可放进,求农夫距离其牛的最大距离的 ...

  7. SOJ 4454 (矩阵快速幂)

    先引入数的快速幂 例如计算2的5次方,常规算法2*2*2*2*2,利用快速幂的思想,求出5的二进制表达式101,权值为1和4的位上数字为1,即2^5=2^1*2^4.代码如下,时间复杂度为O(logn ...

  8. UEFI 下安装 ubuntu 及 win8 双系统 的一些事

    给电脑原装的win8系统装Ubuntu 出现了好多问题,重装多次,刷坏一块主板后,(都是泪啊...) 终于成功. 可能的问题 1:win8 系统下进入 blos 解决方案  1)关闭快速启动:管理员命 ...

  9. codevs——1009 产生数

    1009 产生数 2002年NOIP全国联赛普及组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 给出一个 ...

  10. 安装adt-bundle-windows-x86-20130917时遇到的问题及解决方法

    最近在上安卓课,老师让我们下载此软件(adt-bundle-windows-x86-20130917.下载压缩后,打开eclipse的时候,会出现以下情况: 这时说明你的jdk还没下载或者下载错位置了 ...