一、题目

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

二、题目的理解

其实所有岛屿构成一个基环树森林。至于为什么,每个图由\(m\)个点\(m\)条边组成,而他又是联通的。所以每个图都是基环树。

三、关于基环树

它是一棵树再连一条边形成的。所以它一般长成这样。



一般的处理方法都是把环找出来,树的管树的,再通过环上的合并。

我这里正好有一个扣环的代码。

void getloop(int u) {
dfn[u] = ++timer;
for (int e = fir[u]; e && !lpcnt; e = edge[e].nxt) {
int v = edge[e].to;
if (v == pre[u]) continue;
if (dfn[v]) {
if (dfn[v] < dfn[u]) continue;
for (int i = v; i != u; i = pre[i]) {
lop[++lpcnt] = i;
inl[i] = true;
}
lop[++lpcnt] = i;
inl[u] = true;
return;
}
pre[v] = u;
getloop(v);
}
}

这个代码是在\(u\)即根的时候判的环(可处理2元环)

四、基环树的直径

这个直径可能有两种情况

1、只位于一颗树内

2、两条树的最长链通过环连接

关于树的直径,不提。

关于第二种情况。

设环上的点的数目为\(m\),设\(sum_i\)为编号为\(i\)的点到编号为\(1\)的点(都是环上的)的距离,设\(f_i\)为编号为\(i\)的树的最长至根的链(同样都是环上的)。我们设所有在环上走的方向均为顺时针,至于逆时针走更远的情况,只要把原数组复制一遍。对于一个点\(i\)只有前\(m-1\)个点可以转移至它。转移方程:\(ans_i=max(sum_i-sum_j+f_i+f_j)\),即为:\(ans_i=max(f_j-sum_j)+sum_i+f_i\),这个东西可以用滑动窗口解决。

五、代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#define fi first
#define se second
using namespace std;
typedef long long LL;
const LL INF = 1e15;
const int MAXN = 1000000;
struct Edge {
int to, nxt, w;
} edge[MAXN + 5 << 1];
bool inl[MAXN + 5];
int ecnt, fir[MAXN + 5], pre[MAXN + 5], dfn[MAXN + 5], timer, n, lpcnt, eid[MAXN + 5], que[MAXN + 5];
pair <int, int> lop[MAXN + 5];
LL sum[MAXN + 5 << 1], ans, mxdis[MAXN + 5], ret;
template <typename T> void read(T &x) {
x = 0; int f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - 48; c = getchar(); }
x *= f;
}
void addedge(int u, int v, int w) {
edge[++ecnt].to = v;
edge[ecnt].nxt = fir[u];
edge[ecnt].w = w;
fir[u] = ecnt;
}
void getloop(int u) {
dfn[u] = ++timer;
for (int e = fir[u]; e && !lpcnt; e = edge[e].nxt) {
int v = edge[e].to;
if (v == pre[u]) continue;
if (dfn[v]) {
if (dfn[v] < dfn[u]) continue;
for (int i = v; i != u; i = pre[i]) {
lop[++lpcnt] = make_pair(i, edge[eid[i]].w);
inl[i] = true;
}
lop[++lpcnt] = make_pair(u, edge[e].w);
inl[u] = true;
return;
}
pre[v] = u;
eid[v] = e;
getloop(v);
}
} //找环并计算距离
void dfs(int u, int fa) {
mxdis[u] = 0;
LL minx = 0, maxx = 0;
for (int e = fir[u]; e; e = edge[e].nxt) {
int v = edge[e].to;
if (v == fa || inl[v]) continue;
dfs(v, u);
mxdis[u] = max(mxdis[u], mxdis[v] + edge[e].w);
if (mxdis[v] + edge[e].w > maxx) {
minx = maxx;
maxx = mxdis[v] + edge[e].w;
} else if (mxdis[v] + edge[e].w > minx)
minx = mxdis[v] + edge[e].w;
}
ans = max(ans, minx + maxx); //求出f[i],并统计第一种情况
}
int main() {
read(n);
for (int u = 1; u <= n; ++u) {
int v, w;
read(v), read(w);
addedge(u, v, w);
addedge(v, u, w);
}
for (int u = 1; u <= n; ++u)
if (!dfn[u]) {
lpcnt = 0;
getloop(u);
ans = 0;
for (int i = 1; i <= lpcnt; ++i) {
dfs(lop[i].fi, 0);
lop[lpcnt + i] = lop[i];
} //复制一遍
int head = 1, tail = 1;
que[1] = 1;
for (int i = 2; i <= lpcnt << 1; ++i) {
while (head <= tail && i - que[head] >= lpcnt) ++head; //去掉距离远的
sum[i] = sum[i - 1] + lop[i - 1].se;
ans = max(ans, mxdis[lop[i].fi] + sum[i] + mxdis[lop[que[head]].fi] - sum[que[head]]);
while (head <= tail && mxdis[lop[que[tail]].fi] - sum[que[tail]] <= mxdis[lop[i].fi] - sum[i]) --tail; //维护最优解
que[++tail] = i;
}
ret += ans;
}
printf("%lld\n", ret);
return 0;
}

【Luogu】P4381 [IOI2008]Island的更多相关文章

  1. P4381 [IOI2008]Island(基环树+单调队列优化dp)

    P4381 [IOI2008]Island 题意:求图中所有基环树的直径和 我们对每棵基环树分别计算答案. 首先我们先bfs找环(dfs易爆栈) 蓝后我们处理直径 直径不在环上,就在环上某点的子树上 ...

  2. 【Luogu】P1613 跑路

    [Luogu]P1613 跑路 一.题目 题目描述 小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零.可是小A偏偏又有赖床的坏毛病.于是为了保住自己的工资 ...

  3. 【Luogu】P3933 Chtholly Nota Seniorious

    [题意]将n*m矩阵分成两个区域,要求满足一定条件,求两区域内部极差较大值最小.n,m<=2000 [算法]二分 [题解]极差的数值满足单调性,所以考虑二分极差. 对于给定的极差,将所有数值排序 ...

  4. 【Luogu】P3930 SAC E#1 - 一道大水题 Knight

    [题目]洛谷10月月赛R1 提高组 [题意]给定n*n棋盘和<=16个棋子,给几个棋子种类和攻击范围,现我方只有一马,求能否吃王. [算法]状压+BFS [题解]16种棋子中,马不能吃马,直接处 ...

  5. 【Luogu】P3927 SAC E#1 - 一道中档题 Factorial

    [题目]洛谷10月月赛R1 提高组 [题意]求n!在k进制下末尾0的个数,n<=1e18,k<=1e16. [题解]考虑10进制末尾0要考虑2和5,推广到k进制则将k分解质因数. 每个质因 ...

  6. 【Luogu】 P3928 SAC E#1 - 一道简单题 Sequence2

    [题目]洛谷10月月赛R1 提高组 [算法]递推DP+树状数组 [题解]列出DP递推方程,然后用树状数组维护前后缀和. #include<cstdio> #include<cstri ...

  7. 【Luogu】【关卡2-3】排序(2017年10月) 【AK】

    任务说明:将杂乱无章的数据变得有规律.有各种各样的排序算法,看情况使用. 这里有空还是把各种排序算法总结下吧.qsort需要会写.. P1177 [模板]快速排序 这个题目懒得写了,直接sort了.. ...

  8. 【Luogu】P3369 【模板】普通平衡树(树状数组)

    P3369 [模板]普通平衡树(树状数组) 一.树状数组 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构. ...

  9. 【题解】Luogu P4381 [IOI2008]Island

    原题传送门 题意:求基环树森林的直径(所有基环树直径之和) 首先,我们要对环上所有点的子树求出它们的直径和最大深度.然后,我们只用考虑在环上至少经过一条边的路径.那么,这种路径在环上一定有起始点和终点 ...

随机推荐

  1. .NET Core原理(不知道怎么命名合适)

    作者:cmliu:.NET Core启动都做了什么 .NET Core默认启动时的流程,您可以将图片另存为,在本地放大查看 .NET Core默认模板都做了些什么,首先贴出模板里面的Program.c ...

  2. 真正的解决IDEA中Tomcat控制台乱码的问题

    真正的解决IDEA中Tomcat控制台乱码的问题 解决方案一 网上看到一个真正的解决方案: 首先要分清是tomcat日志编码,与idea的日志显示控制台编码 tomcat日志编码:当在cmd中启动To ...

  3. 吴恩达《深度学习》-第一门课 (Neural Networks and Deep Learning)-第三周:浅层神经网络(Shallow neural networks) -课程笔记

    第三周:浅层神经网络(Shallow neural networks) 3.1 神经网络概述(Neural Network Overview) 使用符号$ ^{[

  4. 一条 SQL 引发的事故,同事直接被开除!!

    前言 Insert into select请慎用. 这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份.本想通过程序先查询查出来然后批量插入.但xxx觉得这样有点慢,需要耗费大量的网络I ...

  5. [LeetCode]394. 字符串解码(栈)

    题目 给定一个经过编码的字符串,返回它解码后的字符串. 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次.注意 k 保证为正整数. ...

  6. myBatis源码解析-二级缓存的实现方式

    1. 前言 前面近一个月去写自己的mybatis框架了,对mybatis源码分析止步不前,此文继续前面的文章.开始分析mybatis一,二级缓存的实现.附上自己的项目github地址:https:// ...

  7. SSM获取SqlSessionFactory

    1.实现类获取session //根据id 修改阈值 public int altThers(threshold threshold) { SqlSessionFactoryBuilder build ...

  8. apisix docker镜像构建及插件化开发

    高能劝退:lua开发,适合小白看!!! 前段时间有个项目,用的java程序做网关,压测tps只有1k多点,惨不忍睹. 后来公司有个大佬改用apisix做网关,tps飙升到1w多. 于是对神奇的apis ...

  9. 4.Scala语法02 - 函数

  10. day55:django:cookie&session

    目录 1.Cookie 1.Cookie前戏 2.Cookie的引入 3.django中操作cookie 2.Session 1.cookie的局限性 2.session技术 3.django操作se ...