Luogu 4244 [SHOI2008]仙人掌图
BZOJ 1023
如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径。
设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f_x + f_y + 1$更新答案,再用$f_y + 1$更新$f_x$。
考虑加入环的情况,保留这个$f_x$的设定。我们可以按照搜索顺序把环上第一个搜到的点看成环的“根”,然后用这个“根”来计算这个环。
假设有环$1, 2, 3, ..., m$,$1$是环的“根”,那么我们可以用$f_i + f_j + min(j - i, m - (j - i))\ (i < j)$来更新答案,然后用$max(f_i + min(i - 1, m - (i - 1)))$来更新$f_1$。
发现这个$min$不怎么好更新,可以断环成链复制一倍,然后用单调队列滑动一个长度为$\left \lfloor \frac{m}{2} \right \rfloor$的区间即可。
在$dfs$的时候保留的$tarjan$时候采用的$dfn$和$low$数组,当$dfn_x < low_y$的时候说明走了一条桥边,按照原来的树形$dp$更新答案。
处理完所有子树之后重新扫一遍儿子,观察是否有$fa_y \neq x$并且$dfn_y > dfn_x$的点,如果有,那么$x$是环的“根”,$y$是环的另一个端点。
时间复杂度应该是$O(n)$吧。
Code:
#include <cstdio>
#include <cstring>
using namespace std; const int N = 5e4 + ;
const int M = 2e5 + ; int n, m, tot = , head[N], f[N], g[N << ], q[N << ];
int ans = , dfsc = , fa[N], dfn[N], low[N], dep[N]; struct Edge {
int to, nxt;
} e[M]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} inline int min(int x, int y) {
return x > y ? y : x;
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} inline void solve(int x, int y) {
int cnt = ;
for(int tmp = y; tmp != x; tmp = fa[tmp])
g[++cnt] = f[tmp];
g[++cnt] = f[x];
for(int i = ; i <= cnt / ; i++)
swap(g[i], g[cnt - i + ]); /* int cnt = dep[y] - dep[x] + 1;
for(int tmp = y; tmp != x; tmp = fa[tmp])
g[cnt--] = f[tmp];
g[cnt] = f[x];
cnt = dep[y] - dep[x] + 1; */
for(int i = ; i < cnt; i++) g[i + cnt] = g[i]; int l = , r = ;
for(int i = ; i < * cnt; i++) {
for(; l <= r && i - q[l] > (cnt / ); ++l);
if(l <= r) chkMax(ans, g[i] + g[q[l]] + i - q[l]);
for(; l <= r && g[q[r]] - q[r] <= g[i] - i; --r);
q[++r] = i;
} for(int i = ; i <= cnt; i++)
chkMax(f[x], g[i] + min(i - , cnt - (i - )));
} void dfs(int x, int fat, int depth) {
fa[x] = fat, dep[x] = depth;
low[x] = dfn[x] = ++dfsc;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
if(!dfn[y]) {
dfs(y, x, depth + );
low[x] = min(low[x], low[y]);
} else low[x] = min(low[x], dfn[y]); if(low[y] > dfn[x]) {
chkMax(ans, f[x] + f[y] + );
chkMax(f[x], f[y] + );
}
} for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
// if(y == fat) continue;
if(fa[y] != x && dfn[y] > dfn[x]) solve(x, y);
}
} int main() {
read(n), read(m);
for(int k, i = ; i <= m; i++) {
read(k);
for(int lst, now, j = ; j <= k; j++) {
read(now);
if(j != ) add(now, lst), add(lst, now);
lst = now;
}
} dfs(, , ); printf("%d\n", ans);
return ;
}
Luogu 4244 [SHOI2008]仙人掌图的更多相关文章
- [SHOI2008]仙人掌图
[SHOI2008]仙人掌图 LG传送门 还不会仙人掌的同学可以看看我对仙人掌知识的一些梳理. 题意就是求仙人掌的直径,直径定义为图中最短路径最长的两点间的最短路径长度. 按照套路,先考虑求树的直径我 ...
- 洛谷 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 ...
- P4244 [SHOI2008]仙人掌图 II
传送门 仙人掌直径,以前好像模拟赛的时候做到过一道基环树的直径,打了个很麻烦的然而还错了--今天才发现那就是这个的弱化版啊-- 如果是树的话用普通的dp即可,记\(f[u]\)表示\(u\)往下最长能 ...
- 洛谷P4244 [SHOI2008]仙人掌图 II
传送门 首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径. 那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并 ...
- 【题解】SHOI2008仙人掌图
本质上还是树形dp.建立圆方树,遇到圆点的时候直接求(和树形dp一样即可),遇到方点做中转点的时候要考虑会从圆的另一侧通过(需满足最短路径的原则).原本是对于圆上的点进行 \(n^{2}\) 的匹配, ...
随机推荐
- IOS socket编程--Asyncsocket
iPhone的标准推荐是CFNetwork 库编程,其封装好的开源库是 cocoa AsyncSocket库,用它来简化CFNetwork的调用,它提供了异步操作 主要特性有: 队列的非阻塞的读和写, ...
- Oracle临时表和SQL Server临时表的不同点对比
文章来源:http://www.codesky.net/article/201109/141401.html 1.简介 Oracle数据库除了可以保存永久表外,还可以建立临时表temporary ta ...
- UIScrollView的左右滑动和侧滑手势冲突的解决办法
转载自:https://blog.csdn.net/kst_123/article/details/77762811 当ViewController中添加了一个全屏的UIScrollView的时候,U ...
- bzoj 3612 [Heoi2014]平衡——整数划分(dp)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3612 因为力矩的缘故,变成了整数划分. 学习到了整数划分.就是那个图一样的套路.https: ...
- 用dwr封装表单项提交表单
首先,配置dwr环境,网上很多资料都说得很详细,这里就不写了. dwr封装form表单项,需要用到dwr定义的一个js方法:DWRUtil.getValues(yourform),这个方法可以返回一个 ...
- 3 SpringBoot与微服务
SpringBoot的使用? 化繁为简: Spring MVC 需要定义各种配置,配置文件多. SpringBoot的核心功能? 独立运行: java -jar XXX.jar (以前启动SPring ...
- cassandra学习 四 数据模型
Keyspace(建空间): 可以理解为Database: Replication factor: 复制因数 : Replica placement srategy: 复制策略,默认是Simple ...
- 为何指针初始化为NULL
指针初始化为NULL,指向NULL指针区(大小64K),如果读取或写入这个地址,会引发内存写保护异常 版权声明:本文为博主原创文章,未经博主允许不得转载.
- 关于Unity发布iOS平台代码混淆问题
之前在越狱手机里找到<永恒战士3>的程序发现是用Unity做的,拷出资源出来看的时候发现里面有游戏程序集,立马抽出来反编译了一下,发现里面的代码只有方法签名,没有方法体,还以为用什么高端混 ...
- java成神之——集合框架之Maps,Hashtable
集合 Maps HashMap 创建和初始化map 遍历方式 LinkedHashMap WeakHashMap TreeMap 线程锁 Hashtable 结语 集合 Maps HashMap Ma ...