题目描述

你将要游览一个有N个岛屿的公园。从每一个岛i出发,只建造一座桥。桥的长度以Li表示。公园内总共有N座桥。尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走。同时,每一对这样的岛屿,都有一艘专用的往来两岛之间的渡船。 相对于乘船而言,你更喜欢步行。你希望所经过的桥的总长度尽可能的长,但受到以下的限制。 • 可以自行挑选一个岛开始游览。 • 任何一个岛都不能游览一次以上。 • 无论任何时间你都可以由你现在所在的岛S去另一个你从未到过的岛D。由S到D可以有以下方法: o 步行:仅当两个岛之间有一座桥时才有可能。对于这种情况,桥的长度会累加到你步行的总距离;或者 o 渡船:你可以选择这种方法,仅当没有任何桥和/或以前使用过的渡船的组合可以由S走到D(当检查是否可到达时,你应该考虑所有的路径,包括经过你曾游览过的那些岛)。 注意,你不必游览所有的岛,也可能无法走完所有的桥。 任务 编写一个程序,给定N座桥以及它们的长度,按照上述的规则,计算你可以走过的桥的最大长度。 限制 2 <= N <= 1,000,000 公园内的岛屿数目。 1<= Li <= 100,000,000 桥i的长度。

输入格式

• 第一行包含N个整数,即公园内岛屿的数目。岛屿由1到N编号。 • 随后的N行每一行用来表示一个岛。第i 行由两个以单空格分隔的整数,表示由岛i筑的桥。第一个整数表示桥另一端的岛,第二个整数表示该桥的长度Li。你可以假设对於每座桥,其端点总是位于不同的岛上。

输出格式

你的程序必须向标准输出写出包含一个整数的单一行,即可能的最大步行距离。 注1:对某些测试,答案可能无法放进32-bit整数,你要取得这道题的满分,可能需要用Pascal的int64或C/C++的long long类型。 注2:在比赛环境运行Pascal程序,由标准输入读入64-bit数据比32-bit数据要慢得多,即使被读取的数据可以32-bit表示。我们建议把输入数据读入到32-bit数据类型。 评分 N不会超过4,000。


题目的第二句话说明了这是一道基环树的题。我们可以按照基环树的套路来做。

我们定义一个东西叫做:基环树的直径。类似于树的直径,它可以理解为:基环树上距离最远的两个点之间的距离。那么直径显然有两种情况:

1.直径是以环上一点为根的子树的直径。

2.直径由环上某两点的子树的最长链加上环上最大距离组成。

为什么叫环上最大距离呢?因为题目是个无向图,所以我们可以顺时针走,也可以逆时针走。

考虑第一种情况

很容易做,直接树形dp或者搜索即可。这里我用的dfs。

考虑第二种情况

设以i为根的子树的最长链长度为dep(i),我们可以列出答案的式子:

\[ ans=Max_{i{\in}loop,j{\in}loop,i{\neq}j}{\{}dep[i]+dep[j]+dist(i,j){\}} \]

最主要就是这个dist怎么算。我们可以用断环成链的技巧,从某个位置开始把环断开,并复制一段到后面去。然后我们计算出环上距离的前缀和sum数组。设环点数为len,那么:

\[ dist(i,j)=Max(sum[i]-sum[j],sum[j+len]-sum[i]); \]

当然我们不需要判断这个max,只需要从1枚举到2倍len即可。带入刚才的式子:

\[ ans=Max_{1≤i≤2*len,1≤j≤2*len,i{\neq}j}{\{}dep[i]+dep[j]+sum[i]-sum[j]{\}} \]

直接算就是O(N^2)的复杂度,显然过不了一百万的数据。考虑到答案式子的这个结构,我们可以想到一种优化:

单调队列优化。只需在枚举i的同时用单调队列维护一段长度为len的区间内dep(j)-sum(j)的最大值即可。

均摊下来复杂度就是O(N)。

*很久前写的代码,码风根现在不大像(我尽量改了一下代码)

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1000005
using namespace std;struct edge{int to, dis, next;edge(){}edge(const int &_to, const int &_dis, const int &_next){to = _to;dis = _dis;next = _next;}
}e[maxn << 1];
int head[maxn], k;struct node{int to;long long w;node(){}node(const int &_to, const long long &_w){to = _to;w = _w;}
}fa[maxn], loop[maxn];int vis[maxn], id, cnt;
long long sum[maxn << 1], dep[maxn << 1], mmax;
int is_c[maxn], now, pos;
int list[maxn << 1], l, r;
int n;inline void add(const int &u, const int &v, const int &w){e[k] = edge(v, w, head[u]);head[u] = k++;
}inline void get_loop(const int &u){vis[u] = ++id;int v;for(int i = head[u]; ~i; i = e[i].next){v = e[i].to;if(v == fa[u].to) continue;if(!vis[v]){fa[v] = node(u, e[i].dis);get_loop(v);}else{if(vis[v] < vis[u]) continue;loop[++cnt] = node(v, e[i].dis);for(; v != u; v = fa[v].to){loop[++cnt] = fa[v];}}}
}inline void dfs(const int &u, const int pre, const long long &w){if(w >= mmax) mmax = w,pos = u;int v;for(int i = head[u]; ~i; i = e[i].next){v = e[i].to;if(v != pre && (!is_c[v] || v == now)) dfs(v, u, w + e[i].dis);}
}inline long long f(const int &i){ return dep[i] - sum[i]; }int main(){memset(head, -1, sizeof head);scanf("%d", &n);int v, w;for(int i = 1; i <= n; i++){scanf("%d%d", &v, &w);add(i, v, w);add(v, i, w);}long long ans = 0, t;for(int i = 1; i <= n; i++) if(!vis[i]){cnt = id = t = 0;get_loop(i);for(int j = 1; j <= cnt; j++) is_c[loop[j].to] = true;for(int j = 1; j <= cnt; j++){mmax = 0,now = -1;dfs(loop[j].to, 0, 0);dep[j] = mmax;now = loop[j].to;dfs(pos, 0, 0);t = max(mmax, t);}for(int j = 1; j <= cnt; j++) dep[j + cnt] = dep[j];l = 1,r = 0;for(int j = 1; j <= cnt << 1; j++){if(j <= cnt) sum[j] = sum[j - 1] + loop[j].w;else sum[j] = sum[j - 1] + loop[j - cnt].w;if(l <= r) t = max(t, f(list[l]) + dep[j] + sum[j]);while(l <= r && f(list[r]) <= f(j)) r--;list[++r] = j;while(l <= r && list[l] <= j - cnt + 1) l++;}ans += t;}printf("%lld\n", ans);return 0;
}

转载于:https://www.cnblogs.com/akura/p/10920107.html

[ioi2008]Island 岛屿相关推荐

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

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

  2. P4381 [IOI2008]Island

    P4381 [IOI2008]Island 题意: 给你一棵基环树森林,求出基环树的直径之和. 题解: 对于基环树,我们将环看作根,那么直径有两种情况:: 1.不经过环,也就是环上某个点的子树内部,对 ...

  3. Leetcode695.Max Area of Island岛屿的最大面积

    给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合.你可以假设二维矩阵的四个边缘都被水包围着. 找到给定的二维数组中 ...

  4. [IOI2008]Island

    题目大意: 找基环树直径 (这个题输入给出的是内向基环树(虽然是无向边)) 存在两种情况: 1.直径在树上. 2.直径从树里走到环上,再走进另外一个树里. 首先dfs找到环. 第一种直接树形dp.dp ...

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

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

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

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

  7. 基础省选+NOI-第4部分 动态规划

    1.期望概率DP [整理]简单的数学期望和概率DP [整理]简单的数学期望和概率DP - nimphy - 博客园 期望&概率dp总结 期望&概率dp总结_十分残念的博客-CSDN博客 ...

  8. 省选+NOI 第一部分 动态规划DP

    期望概率DP [整理]简单的数学期望和概率DP [整理]简单的数学期望和概率DP - nimphy - 博客园 期望&概率dp总结 期望&概率dp总结_十分残念的博客-CSDN博客 期 ...

  9. 数据结构之基环树——骑士,Island,旅行加强版,Number of Simple Paths,Traffic Network in Numazu,Card Game

    文章目录 [ZJOI2008]骑士 [IOI2008] Island [NOIP2018 提高组] 旅行 加强版 CF1454E Number of Simple Paths Traffic Netw ...

最新文章

  1. 大数据时代,谁的眼神锁定你?
  2. 十亿级流量下,我与Redis时延小突刺的战斗史
  3. 2018全球科技创新报告
  4. Core Text 入门
  5. Spring Boot 揭秘与实战(二) 数据缓存篇 - EhCache
  6. mac mysql premium_详解 Navicat Premium Mac 版常用功能
  7. 传统MapReduce框架
  8. iOS开发:iPhone6、6 plus适配
  9. Seeed Raspberry Pi广角摄像/相机模块 支持Pi所有版本 OV5647
  10. python3.7.2安装与配置_python3.7.0 安装与配置
  11. ubuntu安装matlab空间不足,Ubuntu安装Matlab方法及命令
  12. 文昌帝君 -- 《文昌帝君阴骘文》
  13. 大神干货:冠军选手分享解题思路,助你轻松突围初赛
  14. 小程序毕设选题参考springboot学生选课小程序 java选课系统小程序 在线选课小程序 选课报名小程序 ssm选课系统 uniapp线上选课报名小程序
  15. 程序员删库跑路案例之 —— 这家网站首页变图片
  16. Tslib1.20和Qt 4.8.4与在ARM开发板上的移植 多点触摸
  17. linux设置spi时钟频率,Linux下S3C2416的SPI设置问题,CLK和MOSI都没有输出,求助
  18. Leetcode_128_Longest Consecutive Sequence
  19. 从《惊涛大冒险》想到的团队领导问题
  20. 《Web安全之机器学习入门》笔记:第九章 9.4 支持向量机算法SVM 检测DGA域名

热门文章

  1. 7.18 day13
  2. sql转化为int类型
  3. C#中通过Selenium定位a标签的问题
  4. 【整理】更改MSSQL默认字符集
  5. Android:手把手教你打造可缩放移动的ImageView(下)
  6. 【转】Oracle当中扫描数据的方法
  7. [转载]网站分析的最基本度量(3)——网站分析工具如何辨别UV
  8. MapXtreme IResultSetFeatureCollection
  9. Android-图像识别项目OpenCV(4):开发思路以及问题
  10. 和菜鸟一起学android4.0.3源码之lcd屏幕背光调节