[SHOI2008]仙人掌图
[SHOI2008]仙人掌图
还不会仙人掌的同学可以看看我对仙人掌知识的一些梳理。
题意就是求仙人掌的直径,直径定义为图中最短路径最长的两点间的最短路径长度。
按照套路,先考虑求树的直径我们是怎么做的。设\(f[i]\)表示\(i\)往下最长链的长度,\(j\)是\(i\)的儿子,转移和更新答案就是(我习惯用\(o\)表示答案):
\]
考虑放到仙人掌上,对于树边直接转移和更新答案;对于非树边,先把环拎出来,可以直接转移,设\(i\)是环顶端的点,\(j\)是环上的其他点,\(k\)是环的大小:
\]
\(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]仙人掌图的更多相关文章
- 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告
P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...
- SHOI2008仙人掌图(tarjan+dp)
Solution 好题啊没的说. 本题需要求出仙人掌的直径,但仙人掌是一个带有简单环的一张图无法直接用树形dp求解,但它有一个好东西就是没有类似环套环的东西,所以我们在处理时就方便了一些. 思路:ta ...
- BZOJ1023:[SHOI2008]仙人掌图——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1023 Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple ...
- [SHOI2008]仙人掌图 II——树形dp与环形处理
题意: 给定一个仙人掌,边权为1 距离定义为两个点之间的最短路径 直径定义为距离最远的两个点的距离 求仙人掌直径 题解: 类比树形dp求直径. f[i]表示i向下最多多长 处理链的话,直接dp即可. ...
- BZOJ1023 SHOI2008 仙人掌图 仙人掌、单调队列
传送门 求仙人掌的直径,可以由求树的直径进行拓展,只需要在环上特殊判断. 沿用求树的直径的DP,对于一条不在任何环内的边,直接像树的直径一样转移,然后考虑环的影响. 设环长为\(cir\),在\(df ...
- Luogu 4244 [SHOI2008]仙人掌图
BZOJ 1023 如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径. 设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f ...
- P4244 [SHOI2008]仙人掌图 II
传送门 仙人掌直径,以前好像模拟赛的时候做到过一道基环树的直径,打了个很麻烦的然而还错了--今天才发现那就是这个的弱化版啊-- 如果是树的话用普通的dp即可,记\(f[u]\)表示\(u\)往下最长能 ...
- 洛谷P4244 [SHOI2008]仙人掌图 II
传送门 首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径. 那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并 ...
- 【题解】SHOI2008仙人掌图
本质上还是树形dp.建立圆方树,遇到圆点的时候直接求(和树形dp一样即可),遇到方点做中转点的时候要考虑会从圆的另一侧通过(需满足最短路径的原则).原本是对于圆上的点进行 \(n^{2}\) 的匹配, ...
随机推荐
- 退出全屏监听ESC事件
fullscreenchange事件 fullscreenchange:当窗口大小改变时触发 isFullscreen:全局变量 window.addEventListener("fulls ...
- docker 的简单使用
运行一个ubuntu容器 咱们要在cenots7操作系统下,以docker下载一个ubuntu image文件,然后以image启动容器 docker pull ubuntu 或者指定版本:docke ...
- 写markdown用于Github上readme.md文件
Markdown 文档地址 http://pan.baidu.com/s/1o6nu9To Markdown还有一系列衍生版本,用于扩展Markdown的功能(如表格.脚注.内嵌HTML等等),这些功 ...
- matlab操作(整理)
http://blog.csdn.net/ysuncn/article/details/1741828 http://zhan.renren.com/h5/entry/3602888498000464 ...
- 【Excel】坐下,VLOOKUP基本操作
坐下,VLOOKUP基本操作 VLOOKUP如何使用我就不在这里详细介绍了,简单说一下好了. 如上图,第一个填写你要查找的值,第二个空选取你查找的范围,第三个空填你要得到第几列的值,最后选 ...
- jenkins + k8s + lnp
前提条件: K8S 已部署好,traefik也部署完成 K8S 集群上都挂载NFS盘,防止jenkins挂掉后配置消失 基础镜像使用 lnp,PHP 5.6.31 nginx/1.8.1 基础镜像 ...
- Linux--面试题-01
1. 在Linux系统中,以 文件 方式访问设备 . 2. Linux内核引导时,从文件 /etc/fstab 中读取要加载的文件系统. 3. Linux文件系统中每个文件用 i节点 来标识. 4. ...
- Memcached与Redis对比,Redis基础笔记回顾
Memcached 1.为什么要把数据存入内存?快 2.Memcached和Redis的区别 (1)Memcached缓存.Redis数据库,Memcached不支持持久化到磁盘 (2)Redis提供 ...
- SQLServer------查询结果为空的列赋默认值
ISNULL(字段,默认值) 如:SELECT ISNULL(name,'无名') FROM [User]
- 死磕salt系列-salt文章目录汇总
死磕salt系列-salt入门 死磕salt系列-salt配置文件 死磕salt系列-salt grains pillar 配置 死磕salt系列-salt 常用modules 死磕salt系列-sa ...