[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}\) 的匹配, ...
随机推荐
- asp.net MVC 使用PagedList.MVC实现分页
在上一篇的EF之DB First中,存在以下的两个问题: 1. 添加/编辑页面显示的是属性名称,而非自定义的名称(如:姓名.专业...) 2. 添加/编辑时没有加入验证 另外数据展示使用分页 @Htm ...
- [翻译] AYVibrantButton
AYVibrantButton https://github.com/a1anyip/AYVibrantButton AYVibrantButton is a stylish button with ...
- [翻译] M13BadgeView
M13BadgeView M13BadgeView is a customizable badge view for iOS applications. The badge is built to b ...
- 批处理文件(Batch Files )
后缀是bat的文件就是批处理文件,是一种文本文件.简单的说,它的作用就是自动的连续执行多条命令,批处理文件的内容就是一条一条的命令. 新建一个批处理abc.bat,里面内容如下:@echo offec ...
- Squid安装配置和使用
文:铁乐与猫 环境 centos 6.5 x64 安装 最简单的一种就是yum安装. yum install squid 版本 rpm -qa | grep squid squid-3.1.23-16 ...
- 题解 P1868 【饥饿的奶牛】
题目链接:P1868 饥饿的奶牛 题面 有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字. 现用汉语翻译为: 有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧 ...
- Java并发:Executor与连接池
概述 首先来说一说java连接池中常用到的几个类:Executor,ExecutorService,ScheduledExecutorService Executor 执行已经提交的任务对象.此接口提 ...
- python第十八课——常用内置函数
常用内置函数:round(): print(round(3.14),round(3.99)) print(round(3145.926,-2),round(413.575,2)) abs(): pri ...
- 检查oracle用户默认密码的账户
1. 检查使用默认用户密码的账号 --11g 通过数据字典SYS.DEFAULT_PWD$或视图DBA_USERS_WITH_DEFPWD select u.username, u.account_s ...
- [AHOI2009]飞行棋
嘟嘟嘟 刚开始想这道题的时候确实很蒙,只想到矩形对边做对应的弧长相等,然后想办法凑出相等的弧长.其实正解很简单,不要去想边,应该想对角线,因为根据初中园的知识,这个矩形的对角线是圆的直径,而直径所对的 ...