[SHOI2008]仙人掌图

LG传送门

还不会仙人掌的同学可以看看我对仙人掌知识的一些梳理。

题意就是求仙人掌的直径,直径定义为图中最短路径最长的两点间的最短路径长度。

按照套路,先考虑求树的直径我们是怎么做的。设\(f[i]\)表示\(i\)往下最长链的长度,\(j\)是\(i\)的儿子,转移和更新答案就是(我习惯用\(o\)表示答案):

\[f[i] = max\{f[j]\} + 1 \qquad o = max\{f[i] + f[j] + 1\}
\]

考虑放到仙人掌上,对于树边直接转移和更新答案;对于非树边,先把环拎出来,可以直接转移,设\(i\)是环顶端的点,\(j\)是环上的其他点,\(k\)是环的大小:

\[f[i] = max\{f[j] + dis(i, j)\}
\]

\(dis(i, j)\)可以用深度差和环大小减深度差的较小值来表示。

更新答案似乎不能直接搞,考虑断环为链,维护个单调队列:如果队首元素超过环大小的一半就出队,用准备进队的元素和队首元素更新答案,如果当前进队元素的\(f\)减去队尾元素的\(f\)大于等于他们在环上的距离就弹出队尾懒得放数学公式了,可以结合代码理解。

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#define R register
#define I inline
#define B 1000000
using namespace std;
const int N = 50003, M = 100003;
char buf[B], *p1, *p2;
I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; }
I int rd() {
R int f = 0;
R char c = gc();
while (c < 48 || c > 57)
c = gc();
while (c > 47 && c < 58)
f = f * 10 + (c ^ 48), c = gc();
return f;
}
int s[N], p[N], d[N], l[N], e[M], q[M], f[N], t, o;
vector <int> g[N];
I int min(int x, int y) { return x < y ? x : y; }
I int max(int x, int y) { return x > y ? x : y; }
void dfs(int x, int h) {
p[x] = h, d[x] = l[x] = ++t;
R int i, y;
for (i = 0; i < s[x]; ++i) {
if (!d[y = g[x][i]])
dfs(y, x), l[x] = min(l[x], l[y]);
else
if (y ^ h)
l[x] = min(l[x], d[y]);
if (l[y] > d[x])
o = max(o, f[x] + f[y] + 1), f[x] = max(f[x], f[y] + 1);
}
for (i = 0; i < s[x]; ++i)
if (p[y = g[x][i]] ^ x && d[x] < d[y]) {
R int j, k = 0, u = 1, v = 0;
for (j = y; j ^ x; j = p[j])
e[++k] = f[j];
e[++k] = f[x], reverse(e + 1, e + k + 1);
for (j = 1; j <= k; ++j)
e[j + k] = e[j];
k <<= 1, q[++v] = 1;
for (j = 2; j <= k; q[++v] = j, ++j) {
while (j - q[u] > (k >> 2) && u <= v)
++u;
if (u <= v)
o = max(o, e[j] + e[q[u]] + j - q[u]);
while (e[j] - e[q[v]] >= j - q[v] && u <= v)
--v;
}
k >>= 1;
for (j = 2; j <= k; ++j)
f[x] = max(f[x], e[j] + min(j - 1, k - j + 1));
}
}
int main() {
R int n = rd(), m = rd(), i, j, k, x, y;
for (i = 1; i <= m; ++i) {
k = rd(), x = rd();
for (j = 1; j < k; x = y, ++j)
y = rd(), g[x].push_back(y), g[y].push_back(x);
}
for (i = 1; i <= n; ++i)
s[i] = g[i].size();
dfs(1, 0), printf("%d", o);
return 0;
}

[SHOI2008]仙人掌图的更多相关文章

  1. 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告

    P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...

  2. SHOI2008仙人掌图(tarjan+dp)

    Solution 好题啊没的说. 本题需要求出仙人掌的直径,但仙人掌是一个带有简单环的一张图无法直接用树形dp求解,但它有一个好东西就是没有类似环套环的东西,所以我们在处理时就方便了一些. 思路:ta ...

  3. BZOJ1023:[SHOI2008]仙人掌图——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1023 Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple ...

  4. [SHOI2008]仙人掌图 II——树形dp与环形处理

    题意: 给定一个仙人掌,边权为1 距离定义为两个点之间的最短路径 直径定义为距离最远的两个点的距离 求仙人掌直径 题解: 类比树形dp求直径. f[i]表示i向下最多多长 处理链的话,直接dp即可. ...

  5. BZOJ1023 SHOI2008 仙人掌图 仙人掌、单调队列

    传送门 求仙人掌的直径,可以由求树的直径进行拓展,只需要在环上特殊判断. 沿用求树的直径的DP,对于一条不在任何环内的边,直接像树的直径一样转移,然后考虑环的影响. 设环长为\(cir\),在\(df ...

  6. Luogu 4244 [SHOI2008]仙人掌图

    BZOJ 1023 如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径. 设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f ...

  7. P4244 [SHOI2008]仙人掌图 II

    传送门 仙人掌直径,以前好像模拟赛的时候做到过一道基环树的直径,打了个很麻烦的然而还错了--今天才发现那就是这个的弱化版啊-- 如果是树的话用普通的dp即可,记\(f[u]\)表示\(u\)往下最长能 ...

  8. 洛谷P4244 [SHOI2008]仙人掌图 II

    传送门 首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径. 那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并 ...

  9. 【题解】SHOI2008仙人掌图

    本质上还是树形dp.建立圆方树,遇到圆点的时候直接求(和树形dp一样即可),遇到方点做中转点的时候要考虑会从圆的另一侧通过(需满足最短路径的原则).原本是对于圆上的点进行 \(n^{2}\) 的匹配, ...

随机推荐

  1. java中如何打war包

    1.利用jdk里的工具   例如我们要打包的文件在D:\Project:运行 cmd: cd D:\Project 进入D:\Project ,然后输入jar -cvf  Project.war *回 ...

  2. HelloAndroid

    Hello Android 代码 button.setOnClickListener { val alertDialog = AlertDialog.Builder(this) alertDialog ...

  3. 3.5星|《硅谷产品》:Facebook网红社区产品经理经验谈

    硅谷产品:36讲直通世界级产品经理 作者是Facebook产品经理,目前负责的具体业务书的扉页上有含糊的介绍,书中没明确说,根据书中内容推测,主要是网红社区. 比较遗憾的是书中作者亲历的案例只有3个. ...

  4. debug的粗略使用(求大神们补充、指教,小渣马上改)

    debug的使用 往往我们在写代码的时候会发现那种很隐秘的bug,一直找找不多,甚至开始怀疑人生.目光扫描和人脑编译又耗时又耗精力又很容易中途乱了脑子,一切得重新来,所以我写了一篇博客来模拟一下检查b ...

  5. css-table属性运用

    最近在工作中遇到了一些不常用的布局,很多使用 CSS table 属性,并结合 ::before,::after 伪元素完成了,使得 HTML 的结构相对更简单,更具有语义性.当 HTML 结构越清晰 ...

  6. Javascript能做什么 不能做什么。

    JavaScript可以做什么?用JavaScript可以做很多事情,使网页更具交互性,给站点的用户提供更好,更令人兴奋的体验. JavaScript使你可以创建活跃的用户界面,当用户在页面间导航时向 ...

  7. 1.5 Community and Conferences(社区和讨论组)+ 私货

    1.5 Community and Conferences(社区和讨论组)+ 私货 下面是一些和科学计算,数据处理相关的Python社群和讨论组,如果有什么问题可以进行提问: pydata: A Go ...

  8. EOS资料收集

    柚子(EOS)可以理解为Enterprise Operation System,即为商用分布式应用设计的一款区块链操作系统.EOS是EOS软件引入的一种新的区块链架构,旨在实现分布式应用的性能扩展.注 ...

  9. Spring源码分析(二)容器基本用法

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 在正式分析Spring源码之前,我们有必要先来回顾一下Spring中最简 ...

  10. 细数用anaconda安装mayavi时出现的各种问题

    这段时间需要利用mayavi做科学数据的处理,因此需要利用到mayavi库,但是官网上面的指示说:如果安装了anaconda,其中自带各种科学库,但是实践中,并没有发现mayavi. 官方网站导航:m ...