【Luogu】P4381 [IOI2008]Island
一、题目
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的更多相关文章
- P4381 [IOI2008]Island(基环树+单调队列优化dp)
P4381 [IOI2008]Island 题意:求图中所有基环树的直径和 我们对每棵基环树分别计算答案. 首先我们先bfs找环(dfs易爆栈) 蓝后我们处理直径 直径不在环上,就在环上某点的子树上 ...
- 【Luogu】P1613 跑路
[Luogu]P1613 跑路 一.题目 题目描述 小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零.可是小A偏偏又有赖床的坏毛病.于是为了保住自己的工资 ...
- 【Luogu】P3933 Chtholly Nota Seniorious
[题意]将n*m矩阵分成两个区域,要求满足一定条件,求两区域内部极差较大值最小.n,m<=2000 [算法]二分 [题解]极差的数值满足单调性,所以考虑二分极差. 对于给定的极差,将所有数值排序 ...
- 【Luogu】P3930 SAC E#1 - 一道大水题 Knight
[题目]洛谷10月月赛R1 提高组 [题意]给定n*n棋盘和<=16个棋子,给几个棋子种类和攻击范围,现我方只有一马,求能否吃王. [算法]状压+BFS [题解]16种棋子中,马不能吃马,直接处 ...
- 【Luogu】P3927 SAC E#1 - 一道中档题 Factorial
[题目]洛谷10月月赛R1 提高组 [题意]求n!在k进制下末尾0的个数,n<=1e18,k<=1e16. [题解]考虑10进制末尾0要考虑2和5,推广到k进制则将k分解质因数. 每个质因 ...
- 【Luogu】 P3928 SAC E#1 - 一道简单题 Sequence2
[题目]洛谷10月月赛R1 提高组 [算法]递推DP+树状数组 [题解]列出DP递推方程,然后用树状数组维护前后缀和. #include<cstdio> #include<cstri ...
- 【Luogu】【关卡2-3】排序(2017年10月) 【AK】
任务说明:将杂乱无章的数据变得有规律.有各种各样的排序算法,看情况使用. 这里有空还是把各种排序算法总结下吧.qsort需要会写.. P1177 [模板]快速排序 这个题目懒得写了,直接sort了.. ...
- 【Luogu】P3369 【模板】普通平衡树(树状数组)
P3369 [模板]普通平衡树(树状数组) 一.树状数组 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构. ...
- 【题解】Luogu P4381 [IOI2008]Island
原题传送门 题意:求基环树森林的直径(所有基环树直径之和) 首先,我们要对环上所有点的子树求出它们的直径和最大深度.然后,我们只用考虑在环上至少经过一条边的路径.那么,这种路径在环上一定有起始点和终点 ...
随机推荐
- python:列表生成式和三元表达式、匿名函数
一.列表生成式 1.列表生成式就是python内置的一种用来生成list的生成式. 比如下面这个例子: l=[] for i in range(10) list.append(i) 生成一个列表要用循 ...
- delphi DBgrid应用全书
在一个Dbgrid中显示多数据库 在数据库编程中,不必要也不可能将应用程序操作的所有数据库字段放入一个数据库文件中.正确的数据库结构应是:将数据库字段放入多个数据库文件,相关的数据库都包含一个唯 ...
- 大写的服,看完这篇你还不懂RocketMQ算我输
目录 RocketMQ介绍 RocketMQ概念 为什么要用RocketMQ? 异步解耦 削峰填谷 分布式事务最终一致性 数据分发 RocketMQ架构 RocketMQ消息类型 普通消息 顺序消息 ...
- [LeetCode]394. 字符串解码(栈)
题目 给定一个经过编码的字符串,返回它解码后的字符串. 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次.注意 k 保证为正整数. ...
- C#开发PACS医学影像处理系统(十四):处理Dicom影像窗宽窗位
概念解释(网络资料): 窗宽: 窗宽指CT图像所显示的CT 值范围.在此CT值范围内的组织结构按其密度高低从白到黑分为16 个灰阶以供观察对比.例如,窗宽选定为100 Hu ,则人眼可分辨的CT值为1 ...
- java之死锁
转载自 https://www.cnblogs.com/xiaoxi/p/8311034.html 一.死锁的定义 多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力.然而,并发执行也带来 ...
- 基于Springboot+Mybatis+Element UI开发的钢贸供应链系统
小蓝钢贸云供应链系统以销售.采购.库存及财务一体化的设计理念,从供应商到客户的销售流程,实现订单.货物.资金的全面管控,并能对成本进行准确的跟踪与分析,为销售决策提供依据. 基于SpringBoot2 ...
- Oracle学习(三)SQL高级--表结构相关(建表、约束)
一.建表语句 CREATE DATABASE(创建数据库) --创建数据库 create database 数据库名字; CREATE TABLE(创建表) --创建表 CREATE TABLE 表名 ...
- [安洵杯 2019]iamthinking&&thinkphp6.0反序列化漏洞
[安洵杯 2019]iamthinking&&thinkphp6.0反序列化漏洞 刚开始是403,扫描以下目录,扫描到三个目录. [18:06:19] 200 - 1KB - /REA ...
- 源码分析 Kafka 消息发送流程
Futuresend(ProducerRecord<K, V> record) Futuresend(ProducerRecord<K, V> record, Callback ...