题目链接:[IOI2008]Island

题目大意:求基环树直径(由于题目的意思其实是类似于每个点只有一个出度,所以在每个联通块中点数和边数应该是相同的,这就是一棵基环树,所以题目给出的图就是一个基环树森林,又由于乘船的操作,可以知道答案就是将所有的直径相加起来的和)

分析:类似于树的直径,我们可以类推出基环树的直径也是有以下两种情况

​ 1、是某个外向树的直径

​ 2、两个点处于两课不同的外向树中(中间横跨了一段环上的边)

​ 我们首先要把环找到

​ 对于1的处理,我们可以对环上的点及其外向树直接进行dfs求解

​ 对于2,我们会稍微复杂一点,首先可以明确的是,这两个点肯定是道他们对应的根节点距离最大的点,我们记以\(u\)为根节点的树中的最大距离是\(dis_u\),再在环上任选一个点,环上到这个点的距离为\(sum_i\)(所有的距离应是同向的),环上的每一条边的距离和为\(sum_{cnt}\),那么答案就应该是这样的

\[ans=max(ans,max(dis_i+dis_j+(sum_i-sum_j),dis_i+dis_j+sum_{cnt}-(sum_i-sum_j)))\]

将其变形可以得到

\[ans=max(ans,max((sum_i+dis[i])-(sum_j-dis[j]),sum_{cnt}-(sum_i-dis[i])+(sum_j+dis[j])))\]

注意到所有的\(dis\)和\(sum\)均已知,且我们保证在处理节点\(i\)之前已经处理了点\(j\),并且通过我们的整理,上面的式子其实只剩下了两种形式:\(sum_i+dis[i]\)和\(sum_i-dis[i]\)

那么为了保证这个最大值,我们可以记录\(mind=min(sum_i-dis[i])\)和\(maxd=max(sum_i+dis[i])\),每次寻找\(ans\)时直接使用这两个值更新答案可以保证最优,同时沿途更新这两个值

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;
struct node{int to,nxt,cost;
}sq[2000100];
int n,head[1000100],cp[1001000],fa[1001000],sq1[1001000][3],all=0,cnt=0;
bool vis[1001000],cir[1001000];
long long dis[1001000],sum[1001000],ans;int read()
{int x=0,f=1;char ch=getchar();while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}return x*f;
}void add(int u,int v,int w)
{all++;sq[all].to=v;sq[all].nxt=head[u];sq[all].cost=w;head[u]=all;
}void init()
{n=read();int i;memset(head,0,sizeof(head));memset(vis,0,sizeof(vis));memset(cir,0,sizeof(cir));memset(dis,0,sizeof(dis));for (i=1;i<=n;i++){int v=read(),w=read();add(i,v,w);add(v,i,w);sq1[i][0]=i;sq1[i][1]=v;sq1[i][2]=w;}
}void findcircle(int u)
{vis[u]=1;cnt=0;while (1){int v=sq1[u][1];if (vis[v]){cp[++cnt]=v;cir[v]=1;int i;sum[cnt]=sq1[v][2];for (i=u;i!=v;i=fa[i]){cir[i]=1;cp[++cnt]=i;sum[cnt]=sq1[i][2];}for (i=1;i<=cnt;i++) sum[i]+=sum[i-1];break;}else {vis[v]=1;fa[v]=u;}u=v;}
}void find_d(int u)
{cir[u]=1;int i;for (i=head[u];i;i=sq[i].nxt){int v=sq[i].to,w=sq[i].cost;if (cir[v]) continue;find_d(v);ans=max(ans,dis[u]+dis[v]+w);dis[u]=max(dis[u],dis[v]+w);}
}long long findans(int u)
{sum[0]=0;findcircle(u);int i;ans=0;long long mind=1e18+7,maxd=-mind;for (i=1;i<=cnt;i++) find_d(cp[i]);for (i=1;i<=cnt;i++){int v=cp[i];ans=max(ans,max(sum[i]+dis[v]-mind,sum[cnt]-(sum[i]-dis[v])+maxd));mind=min(mind,sum[i]-dis[v]);maxd=max(maxd,sum[i]+dis[v]);}//cout << 1;//for (i=1;i<=n;i++) cout << vis[i] << " ";cout << endl;return ans;
}void work()
{long long sumans=0;int i;for (i=1;i<=n;i++) if (!cir[i]) sumans+=findans(i);printf("%lld",sumans);
}int main()
{init();work();return 0;
}
/*
7
3 8
7 2
4 2
1 4
1 9
3 4
2 3
*/

转载于:https://www.cnblogs.com/encodetalker/p/9977391.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. [IOI2008]Island

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

  4. [ioi2008]Island 岛屿

    题目描述 你将要游览一个有N个岛屿的公园.从每一个岛i出发,只建造一座桥.桥的长度以Li表示.公园内总共有N座桥.尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走.同时,每一对这样的岛屿,都有一 ...

  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. 数据结构之基环树——骑士,Island,旅行加强版,Number of Simple Paths,Traffic Network in Numazu,Card Game

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

  8. java异步处理同步化_java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring EventListener,超时处理和空循环性能优化...

    异步转同步 业务需求 有些接口查询反馈结果是异步返回的,无法立刻获取查询结果. 正常处理逻辑 触发异步操作,然后传递一个唯一标识. 等到异步结果返回,根据传入的唯一标识,匹配此次结果. 如何转换为同步 ...

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

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

  10. android studio 混淆包,gogoapp体育-官网首页

    一.密码 1.在阅读项目代码时,对于 #pragma warning(disable : 4251) 这个语句不是很理解,现在有时间查阅了一些资料整理如下,以备以后查找使用,也给对此有疑问提的朋友一个 ...

最新文章

  1. ecshop 属性自动组合_【深度文章】结构设计中的荷载组合剖析(下)
  2. Vim YouCompleteMe 安装配置
  3. pymc3 贝叶斯线性回归_使用PyMC3估计的贝叶斯推理能力
  4. Linux使用笔记: 设置Samba服务器中新建文件/目录的权限
  5. 使用firefox44版本,弃用chrome
  6. 形式语义学-JLU-ZHH
  7. 云上直播性能优化及测试方案详解
  8. 效果实现JS实现飞雪飘飘的效果
  9. jQuery conflict with other Liberary
  10. 网络术语还在困扰你吗?
  11. 在线考试系统详细设计
  12. 王之泰201771010131《面向对象程序设计(java)》第十七周学习总结
  13. 使用docx4j追尾合并多个docx文件为一个docx文件
  14. 2022年最全软件测试面试题加答案,毫不夸张的说,学完面试涨薪5K
  15. 网上作业批改系统的设计与实现(JSP,MySQL)
  16. 18个无版权(免费可商用)图片网站
  17. 模具设计分型的10大原则
  18. U盘用作启动盘后空间变为原来的一半
  19. PTA-L1-034微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。本题就要求你写个程序,通过统计一个人点赞的
  20. WhatsApp客服系统,为什么使用SendWS拓客系统实现WhatsApp客服系统多账号管理?

热门文章

  1. PHP学习日记0_PHP、静态网页、动态网页、静态网站访问流程、动态网站访问流程
  2. 解决 Minimum supported Gradle version is 5.1.1. Current version is 4.6 以及最终apk打包输出
  3. 在线 excel 产品技术调研
  4. (八)Mybatis当中#{}常用属性的用法
  5. 键盘的故事,程序员的故事,成长的故事
  6. 复数乘法的交换律、结合律及乘法 对加法的分配律证明过程
  7. 网秦安全盾 原理分析
  8. python docx首行缩进两字符的设定方法
  9. [转] 怎样写好作文批语
  10. xcode5 自定义模板