一道基环树的直径

BZOJ原题链接

洛谷原题链接

又是一道实现贼麻烦的题。。

显然公园其实是基环树森林,求的最长距离其实就是求每一棵基环树的直径的总和。

对于每棵基环树,其直径要么经过环,要么是某个环上点的子树的直径。所以我们可以先找出它的环,然后对环上的每个点进行\(dfs\)(不能经过环上的点),找出该点的子树的直径和数组\(D\),表示该点到子树中的叶子节点的最大距离。

然后考虑经过环的距离,设当前枚举到两个点\(x,y\),则长度为\(D[x]+D[y]+dis(x,y)\),这个可以通过单调队列来优化,维护一个最大值即可。

#include<cstdio>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
int fi[N], di[N << 1], da[N << 1], ne[N << 1], cr[N], cr_d[N], q[N << 1], po[N << 1], l, cb, fp, n;
ll D[N], dis[N << 1], fr;
bool v[N], egv[N << 1], vis[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c<'0' || c>'9'; c = getchar())
p |= c == '-';
for (; c >= '0'&&c <= '9'; c = getchar())
x = x * 10 + (c - '0');
return p ? -x : x;
}
inline void add(int x, int y, int z)
{
di[++l] = y;
da[l] = z;
ne[l] = fi[x];
fi[x] = l;
}
inline ll maxn(ll x, ll y)
{
return x > y ? x : y;
}
void dfs(int x)
{
int i, y;
v[x] = 1;
for (i = fi[x]; i; i = ne[i])
{
y = di[i];
if (!egv[i])
{
cr[y] = x;
cr_d[y] = da[i];
egv[i] = egv[i & 1 ? i + 1 : i - 1] = 1;
if (v[y])
cb = y;
dfs(y);
}
}
}
void dfs_2(int x, ll d, int fa)
{
int i, y;
if (fr < d)
{
fr = d;
fp = x;
}
for (i = fi[x]; i; i = ne[i])
{
y = di[i];
if (!vis[y] && y != fa)
{
dfs_2(y, d + da[i], x);
D[x] = maxn(D[x], D[y] + da[i]);
}
}
}
void dfs_3(int x, ll d, int fa)
{
int i, y;
fr = maxn(fr, d);
for (i = fi[x]; i; i = ne[i])
{
y = di[i];
if (!vis[y] && y != fa)
dfs_3(y, d + da[i], x);
}
}
int main()
{
int i, j, x, y, k, head, tail;
ll s = 0, ma;
n = re();
for (i = 1; i <= n; i++)
{
x = re();
y = re();
add(i, x, y);
add(x, i, y);
}
for (i = 1; i <= n; i++)
if (!v[i])
{
ma = 0;
dfs(i);
j = cb;
k = 0;
do
{
vis[j] = 1;
k++;
dis[k + 1] = dis[k] + cr_d[j];
po[k] = j;
j = cr[j];
} while (j^cb);
do
{
vis[j] = 0;
fr = 0;
dfs_2(j, 0, 0);
fr = 0;
dfs_3(fp, 0, 0);
vis[j] = 1;
ma = maxn(ma, fr);
k++;
dis[k + 1] = dis[k] + cr_d[j];
po[k] = j;
j = cr[j];
} while (j^cb);
head = 1;
tail = 0;
for (j = 1; j <= k; j++)
{
while (j - q[head] >= (k >> 1))
head++;
if (head <= tail)
ma = maxn(ma, D[po[j]] + D[po[q[head]]] + dis[j] - dis[q[head]]);
else
ma = maxn(ma, D[po[j]]);
while (head < tail&&D[po[j]] - dis[j] >= D[po[q[tail]]] - dis[q[tail]])
tail--;
q[++tail] = j;
}
s += ma;
}
printf("%lld", s);
return 0;
}

BZOJ1791或洛谷4381 [IOI2008]Island的更多相关文章

  1. luogu 4381 [IOI2008]Island 单调队列 + 基环树直径 + tarjan

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

  2. BZOJ1791: [Ioi2008]Island 岛屿

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

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

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

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

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

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

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

  6. 【洛谷3224/BZOJ2733】[HNOI2012]永无乡 (Splay启发式合并)

    题目: 洛谷3224 分析: 这题一看\(n\leq100000\)的范围就知道可以暴力地用\(O(nlogn)\)数据结构乱搞啊-- 每个联通块建一棵Splay树,查询就是Splay查询第k大的模板 ...

  7. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  8. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  9. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

随机推荐

  1. IDEA导入jar包

    http://blog.csdn.net/a153375250/article/details/50851049

  2. CSS 原理

    CSS是一个描述HTML文档的样式语言. CSS描述HTML元素的显示方式. 本教程将教你CSS从基础到网页布局,学完本教程,可以设计出漂亮的网站. 本教程需要HTML知识为基础,学习HTML前往&l ...

  3. boot中 Quartz注入spring管理类失败

    在项目中用到了Quartz,想在里面实现业务操作发现sping类注入总是失败.后来网上查询了一下解决办法.下面把我成功解决问题的这个版本发出来,大家一起学习一下. 在quartz 会发现 job中无法 ...

  4. pandas.DataFrame.to_excel

    1. file_name = 'aa.xlsx' df.to_excel(file_name) #这种file_name不能重复,已经生成过的就会报错 writer = pd.ExcelWriter( ...

  5. 对象转化为json

    google开发的Gson转换利器,String json = new Gson ().toJson(object); 一行代搞定. 别忘了引入jar包 转自:https://zhidao.baidu ...

  6. 如何正确获取MYSQL的ADO连接字符串

    首先你正确安装了MYSQL的数据库驱动程序(mysql-connector-odbc-5.3.2-win32.msi )http://dev.mysql.com/downloads/connector ...

  7. Linux查看修改时间、时区

    同步网络时间 yum install ntpntpdate time.nist.gov timedatectl set-timezone Asia/Shanghai如果上面time.nist.gov服 ...

  8. Python3 round() 函数

    Python3 round() 函数  Python3 数字 描述 round() 方法返回浮点数x的四舍五入值. 语法 以下是 round() 方法的语法: round( x [, n] ) 参数 ...

  9. Python+Selenium学习--访问连接

    场景 web UI测试里最简单也是最基本的事情就是访问1个链接了. 在python的webdrive中,访问url时应该使用get方法. 代码 #!/usr/bin/env python # -*- ...

  10. Linux基石【第三篇】vim提示-bash:vim :common not found解决方法

    在Linux命令行输入vim时提示:-bash:vim :common not found,之后按着查询到的解决办法整好了: 解决步骤如下: 1.输入 rpm -qa|grep vim 命令,查看返回 ...