传送门

显然题目给的图构成一个基环树森林

对于每个基环树单独考虑,显然每个都走直径是最优的

考虑如何求出基环树的直径

把直径分为两种情况考虑,首先可以找出环

因为直径可能不在环边上,所以对每个环上节点的子树进行一遍 $dfs$,求出每个节点子树的直径

维护 $dis[x]$ 表示节点 $x$ 到叶子节点的最长路程,那么直径就是每个节点儿子的 $dis$ 中最大和次大的和

可以一遍循环动态维护最大和次大

直径也可能在环上

设环上两点 $x,y$ 的距离为 $d(x,y)$,那么就是求最大的 $dis[x]+dis[y]+d(x,y)$

这样复杂度是 $O(n^2)$,考虑优化

按照套路,考虑把环断成链:

维护一条链上的距离前缀和 $sum[\ ]$,设 $y$ 在 $x$ 后面,那么就是求直径就是 $dis[x]+dis[y]+sum[y]-sum[x]$

换一下,就是求对于每一个 $y$,求链上区间 $x\in(y-n,y)$ 的 $(dis[x]-sum[x])$ 最大值 $+(dis[y]+sum[y])$($n为环的节点数$)

显然这个东西我们可以单调队列优化

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=1e6+;
int fir[N],from[N<<],to[N<<],val[N<<],cntt;
inline void add(int a,int b,int c)
{
from[++cntt]=fir[a]; fir[a]=cntt;
to[cntt]=b; val[cntt]=c;
}
struct edge{
int v,w;//节点,边权
}To[N];//To存题目给出的数据
int n,tot,ring[N],d[N];//ring存环上节点,d存环上节点到下一环上节点的边的边权
ll ANS;
int fa[N];//存环节点的'父'节点
bool vis[N],p[N];//vis判断是否为走过的基环树节点,p判断是否是基环树环节点
void BFS(int x)//找环
{
tot=; vis[x]=; int t;
while()
{
t=To[x].v;
if(vis[t])//找到就一路回跳并更新ring,d,p
{
ring[++tot]=t; d[tot]=To[t].w; p[t]=;
for(int i=x;i!=t;i=fa[i])
p[i]=,ring[++tot]=i,d[tot]=To[i].w;
return;
}
vis[t]=; fa[t]=x; x=t;//否则就继续找
}
}
ll dis[N],res;//维护当前基环树直径
void dfs(int x,int f)//处理dis和子树直径最大值
{
vis[x]=;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(p[v]||v==f) continue;
dfs(v,x); res=max(res,dis[x]+dis[v]+val[i]);
//此时dis[x]还没有dis[v]+val[i],所以res可以这样更新
dis[x]=max(dis[x],dis[v]+val[i]);//更新dis
}
}
int Q[N<<]; ll sum[N<<];
inline int id(int x) { return (x-)%tot+; }//把链节点换成环节点
inline ll calc(int x) { return dis[ring[id(x)]]-sum[x]; }
inline void solve()//单调队列
{
int l=,r=;
for(int i=;i<=(tot<<);i++)
{
sum[i]=sum[i-]+d[id(i)];
while(l<=r && i-Q[l]>=tot ) l++;
if(l<=r) res=max(res,calc(Q[l])+sum[i]+dis[ring[id(i)]]);//先更新res
while(l<=r && calc(i)>=calc(Q[r]) ) r--;//再更新队列
Q[++r]=i;
}
}
int main()
{
n=read(); int a,b;
for(int i=;i<=n;i++)
{
a=read(),b=read();
add(i,a,b); add(a,i,b);
To[i].v=a; To[i].w=b;
}
for(int i=;i<=n;i++)
{
if(vis[i]) continue;
BFS(i); res=;
for(int j=;j<=tot;j++) dfs(ring[j],);
solve(); ANS+=res;
}
printf("%lld",ANS);
return ;
}

P4381 [IOI2008]Island的更多相关文章

  1. P4381 [IOI2008]Island(基环树+单调队列优化dp)

    P4381 [IOI2008]Island 题意:求图中所有基环树的直径和 我们对每棵基环树分别计算答案. 首先我们先bfs找环(dfs易爆栈) 蓝后我们处理直径 直径不在环上,就在环上某点的子树上 ...

  2. 【题解】Luogu P4381 [IOI2008]Island

    原题传送门 题意:求基环树森林的直径(所有基环树直径之和) 首先,我们要对环上所有点的子树求出它们的直径和最大深度.然后,我们只用考虑在环上至少经过一条边的路径.那么,这种路径在环上一定有起始点和终点 ...

  3. 【Luogu】P4381 [IOI2008]Island

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

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

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

  5. IOI2008 island

    题目链接:[IOI2008]Island 题目大意:求基环树直径(由于题目的意思其实是类似于每个点只有一个出度,所以在每个联通块中点数和边数应该是相同的,这就是一棵基环树,所以题目给出的图就是一个基环 ...

  6. bzoj千题计划114:bzoj1791: [Ioi2008]Island 岛屿

    http://www.lydsy.com/JudgeOnline/problem.php?id=1791 就是求所有基环树的直径之和 加手工栈 #include<cstdio> #incl ...

  7. BZOJ1791: [Ioi2008]Island 岛屿

    BZOJ1791: [Ioi2008]Island 岛屿 Description 你将要游览一个有N个岛屿的公园. 从每一个岛i出发,只建造一座桥. 桥的长度以Li表示. 公园内总共有N座桥. 尽管每 ...

  8. [题解] LuoguP4381 [IOI2008]Island

    LuoguP4381 [IOI2008]Island Description 一句话题意:给一个基环树森林,求每棵基环树的直径长度的和(基环树的直径定义与树类似,即基环树上一条最长的简单路径),节点总 ...

  9. [bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)

    [bzoj1791][ioi2008]Island 岛屿(基环树.树的直径) bzoj luogu 题意可能会很绕 一句话:基环树的直径. 求直径: 对于环上每一个点记录其向它的子树最长路径为$dp_ ...

随机推荐

  1. Android 创建项目出现No resource found that matches the given name Theme.AppCompat.Light

    关于为何出现No resource found that matches the given name ‘Theme.AppCompat.Light’的原因 这边博客已经写的很清楚了 大家可以参考一下 ...

  2. Solidity payable 方法表现

    pragma solidity ^; contract Person { string public name; uint age; uint private weight; string inter ...

  3. java类中final方法的作用

    不给子类复写这个方法.说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用 inline扩展 ...

  4. 方向ajax(http long request实现实时通信)

    现在我们就要通过这种方法来实现实时通信,先说一下原理: 客户端发起一个ajax长链接查询,然后服务端就开始执行代码,主要是检查某个文件是否被更新,如果没有,睡一会(sleep),醒来接着检查 如果客户 ...

  5. 简单的Cookie记录浏览记录案例

    books.jsp 界面 代码 <%@ page contentType="text/html;charset=UTF-8" language="java" ...

  6. JAVA8 Lambda 表达式使用心得

    List<HashMap> 指定数据求和: List<HashMap> kk = new ArrayList<>();        Map mmm = new H ...

  7. 如何使用 channel

    如何使用 Channel 例子来自于Concurrency is not parallelism Google Search: A fake framework v1.0 var ( Web = fa ...

  8. ecliplse启动慢的优化方法(亲测有效)

    本人使用的ecliplse IDE 版本是: Version: Photon Release (4.8.0)Build id: 20180619-1200 我的电脑配置是 Ecliplse启动差不多一 ...

  9. php代码审计7审计csrf漏洞

    跨站请求伪造,也有人写出xsrf,黑客伪造用户的http请求,然后将http请求发送给存在csrf的网站,网站执行了伪造的http请求,就引发了跨站请求伪造 漏洞危害:攻击者盗用了你的身份信息,以你的 ...

  10. spring 学习(二):spring bean 管理--配置文件和注解混合使用

    spring 学习(二)spring bean 管理--配置文件和注解混合使用 相似的,创建 maven 工程,配置pom.xml 文件,具体可以参考上一篇博文: sprint 学习(一) 然后我们在 ...