一、题目

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. delphi DBgrid应用全书

    在一个Dbgrid中显示多数据库    在数据库编程中,不必要也不可能将应用程序操作的所有数据库字段放入一个数据库文件中.正确的数据库结构应是:将数据库字段放入多个数据库文件,相关的数据库都包含一个唯 ...

  2. 《Java从入门到失业》第四章:类和对象(4.1):初识类和对象

    4类和对象 在第一章曾经简单介绍过,在面向对象的世界里,一切事物皆对象,当解决一个问题的时候,我们先会考虑这个问题会涉及到哪些事物,然后把事物抽象成类,当时还画了一张图如下: 从本章开始,我们一点一点 ...

  3. pytest测试框架 -- 简介

    一.pytest测试框架简介: (1)pytest是python的第三方测试框架,是基于unittest的扩展框架,比unittest更简洁,更高效. (2)pytest框架可以兼容unittest用 ...

  4. linux 字符驱动框架(用户态的read,write,poll是怎么操作驱动的)

    前言 这篇文章是通过对一个简单字符设备驱动的操作来解释,用户态的读写操作是怎么映射到具体设备的. 因为针对不同版本的linux内核,驱动的接口函数一直有变化,这贴出我测试的系统信息: root@ubu ...

  5. 第18课 - make 中的路径搜索(下)

    第18课 - make 中的路径搜索(下) 1. 问题一 当 VPATH 和 vpath 同时出现,make 会如何处理? 工程项目的目录结构如下图所示,src1 和 src2 中都包含了 func. ...

  6. 痞子衡嵌入式:MCUXpresso IDE下添加C++源文件进SDK工程编译的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso IDE下添加C++源文件进SDK工程编译的方法. 最近有客户反映在MCUXpresso IDE下的SDK工程里添加 ...

  7. mariadb 4

    连接查询,视图,事物,索引,外键(第四章)   连接查询 --创建学生表 create table students ( id int unsigned not null auto_increment ...

  8. OKR工作法

    OKR 目标与关键成果 [Objectives and Key Results] OKR是目标管理工具,它的价值不在于是否完成OKR,而在于呈现出团队最应该关注的事情,通过持续性的沟通确保每个人都聚焦 ...

  9. 探讨PostgreSQL实例中数据库之间的关系

    疑问 前几天PG学习微信群有人在问"pg_class 存储了对象和命名空间,表空间的对应关系,为什么没有和数据库的关系?我想查数据库下面有多少对象,找不到数据库和对象的关系?" 简 ...

  10. 2018尚硅谷最新SpringCloud免费视频教程

    [课程内容] 01.前提概述 02.大纲概览 03.从面试题开始 04.微服务是什么 05.微服务是什么2 06.微服务与微服务架构 07.微服务优缺点 08.微服务技术栈有哪些 09.为什么选择Sp ...