P4381 [IOI2008]Island

题意:

给你一棵基环树森林,求出基环树的直径之和.

题解:

对于基环树,我们将环看作根,那么直径有两种情况::

1.不经过环,也就是环上某个点的子树内部,对于这种情况,直接在子树内部处理直径,更新答案即可;

2.经过环,答案就是i的子树内长度+j的子树内长度+i和j之间的距离,我们预处理出环上每个点到其子树上的最长距离,在预处理一个环上前缀和,ans=max{sondis[i]+sondis[j]+sumcircle[i]-sumcircle[j]},更新答案即可.
sondis[i]记录环上的第i个点到其子树的最远距离;
sumcircle[]记录环上距离前缀和;
sumcircle[i]-sumcircle[j]即为i和j的距离

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e6+3;
int to[N<<1],nex[N<<1],head[N],w[N<<1],tt;
int c[N];//记录当前节点属于第几棵基环树;
int dg[N];//记录度数;
int q[N<<1];//数组模拟队列;
ll d[N];//d[i]记录第i棵树上的直径;
ll f[N];//f[i]记录从i点向儿子方向上所可以走的最长距离;
ll sumcircle[N<<1];//环上距离前缀和;
ll sondis[N<<1];//sondis[i]记录环上的第i个点到其子树的最远距离;
int cnt,n;
bool vis[N];//标记当前基环树是否已解决过;
inline void add(int x,int y,int W){to[++tt]=y,w[tt]=W,nex[tt]=head[x],head[x]=tt;return ;
}
inline void bfs(int p,int t){int l=0,r=1;q[1]=p,c[p]=t;//广搜预处理每一个点所属基环树的编号;while(l<r){++l;int x=q[l];for(int i=head[x],v;i;i=nex[i]){v=to[i];if(!c[v]){q[++r]=v;c[v]=t;}}}return ;
}
inline void top_sort(){//拓扑排序求不经过环的直径,从叶子节点向根(环)遍历;int l=0,r=0;for(int i=1;i<=n;++i)if(dg[i]==1)q[++r]=i;//将所有度数为1的点先加入队列中(即叶子结点);while(l<r){++l;int x=q[l];for(int i=head[x],v;i;i=nex[i]){v=to[i];if(dg[v]>1){//此时v在以环为根的树上是其实是x的父亲;d[c[x]]=max(d[c[x]],f[x]+f[v]+w[i]);//更新当前基环树上的答案;f[v]=max(f[v],f[x]+w[i]);//更新父节点可以到达的最远节点;if(--dg[v]==1)q[++r]=v;//若当前度数现在变为1,入队;}}}return ;
}
inline void work(int t,int x){int tot=0,l,r,v=x,u,i;//在拓扑排序后已经将非环上的边遍历完了,环上的边和点均还未遍历,且度数为2,将x看做环上的起点,v看做终点;do{dg[v]=1;sondis[++tot]=f[v];//将当前点度数记为1,防止反向遍历,同时记录第tot号环上节点到子树上的最短距离;for(i=head[v];i;i=nex[i]){u=to[i];if(dg[u]>1){//环上的点度数均大于1,所以度数大于1的点即是环上的点;v=u;//更新终点;sumcircle[tot+1]=sumcircle[tot]+w[i];//处理环上距离前缀和;break;//保证向一边枚举,所以找到一个点就break;}}}while(i);if(tot==2){//特殊处理二元环;int len=0;for(i=head[v];i;i=nex[i]){u=to[i];if(u==x){len=max(len,w[i]);//找出两个点之间较大的边; }}d[t]=max(d[t],(ll)len+f[x]+f[v]);//更新答案;return ;}for(int i=head[v],u;i;i=nex[i]){u=to[i];if(u==x){sumcircle[tot+1]=sumcircle[tot]+w[i];//将起点和终点的距离处理出来;break;}}for(i=1;i<tot;i++)//断环为链,再复制一遍数组;{sondis[tot+i]=sondis[i];sumcircle[tot+i]=sumcircle[tot+1]+sumcircle[i];}q[1]=1;l=r=1;for(int i=2;i<tot<<1;++i){while(l<=r&&i-q[l]>=tot)++l;//将超出环长度的部分弹出;d[t]=max(d[t],sondis[q[l]]+sondis[i]+sumcircle[i]-sumcircle[q[l]]);while(l<=r&&sondis[q[r]]+sumcircle[i]-sumcircle[q[r]]<=sondis[i])--r;//将队尾答案不够优秀的部分弹出;q[++r]=i;//入队;}return ;
}
int main(){cin>>n;int x,W;for(int i=1;i<=n;++i){scanf("%d%d",&x,&W);add(x,i,W);add(i,x,W);++dg[x];++dg[i];}for(int i=1;i<=n;++i)if(!c[i])bfs(i,++cnt);//预处理;top_sort();//拓扑排序求直径;ll ans=0;for(int i=1;i<=n;++i)if(dg[i]>1&&!vis[c[i]]){//如果当前基环树未被处理,并且当前点是环上点,就处理;vis[c[i]]=true;work(c[i],i);ans+=d[c[i]];//累加答案;}cout<<ans<<'\n';return 0;
}

P4381 [IOI2008]Island相关推荐

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

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

  2. [IOI2008]Island

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

  3. [ioi2008]Island 岛屿

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

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

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

  5. 2019年二月刷题列表

    Preface 虽然二月剩下没多少了,但是为了勉强保持格式还是写一写吧 这个月的首要目标就是在剩下的时间里让这个月的做题数争取达到\(50\),不过感觉希望渺茫啊 初三中考百天倒计时要来了,所以为此我 ...

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

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

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

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

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

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

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

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

最新文章

  1. Nature综述——真菌的多样性:真菌的高通量测序及鉴定
  2. 微擎pc 导入前缀_段覆盖前缀| 8086微处理器
  3. 简易的遍历文件加密解密
  4. 使用流进行通讯的一种可能犯的错误 (InputStream + OutputStream)
  5. SpringBoot集成Redis缓存
  6. 计算点在哪些四边形内
  7. java面试题(分布式篇)
  8. coreseek mysql_centos+php+coreseek+sphinx+mysql之一coreseek安装篇
  9. Steam忘记账号如何在文件夹中找回
  10. 二阶、三角、三阶、四阶、五阶魔方还原方法总结
  11. win10系统mysql重新配置密码
  12. 2020西湖论剑Web复现
  13. 尚硅谷YYDS (课件资料)
  14. 广告竞价-广义第二出价
  15. zzulioj1197 考试排名(一)(结构体专题)
  16. [奥运] 28届奥运会中国队奖牌一览
  17. Spring MVC使用篇(八)—— 处理器(Handler)方法的返回值
  18. Java HMAC-SHA1加密算法的实现
  19. win10电脑解决 SYSTEM_THREAD_EXCEPTION_NOT_HANDLED 蓝屏
  20. 恒指市场新手的困惑,最新战法来解决。

热门文章

  1. 复工后,看看他们都是怎么上班的!
  2. 计算机广告制作未来发展还行吗,计算机多媒体设计专业和广告设计制作那个好...
  3. android ifw 启动广告,使用 IFW 完全控制 Android 应用行为 | 实用技巧
  4. android宿舍管理系统源码,基于android操作系统的手机宿舍管理系统使用手册
  5. python赋值语句格式_Python赋值语句后逗号的作用分析
  6. micropython 网络驱动_network_网卡驱动
  7. java中week of year_Java WeekFields weekOfYear()用法及代码示例
  8. .md是什么文件_Element-UI源码阅读之md显示到页面
  9. java转python推荐算法_java和python实现一个加权SlopeOne推荐算法
  10. mysql java驱动 ibm_JDBC驱动汇总