题意

求仙人掌的直径(相距最远的两个点的距离)。

\(n\le 5\times 10^4​\)

分析

  • 建立圆方树,讨论答案路径的 lca 在圆点还是方点。
  • 利用树形 dp 求出每个圆点到 不同子树内圆点 的最长距离与次长距离 \(f_{i,0},f_{i,1}\)。
  • 如果答案以某个圆点作为 lca,答案是 \(f_{i,0}+f_{i,1}\) 。
  • 否则,将一个方点的圆点子节点拿出来,倍长链后利用单调队列找到最优的两个圆点即可。
  • 复杂度 \(O(n)​\) 。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi() {
int x = 0,f = 1;
char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
return x * f;
}
template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
const int N = 1e5 + 7;
int n, m, edc, dfn, tp, ndc, ans;
int low[N], pre[N], stk[N], f[N][2], head[N];
vector<int>G[N];
struct edge {
int lst, to;
edge(){}edge(int lst, int to):lst(lst), to(to){}
}e[N << 1];
void Add(int a, int b) {
e[++edc] = edge(head[a], b), head[a] = edc;
e[++edc] = edge(head[b], a), head[b] = edc;
}
void tarjan(int u, int fa) {
low[u] = pre[u] = ++dfn;
stk[++tp] = u;
go(u)if(v ^ fa) {
if(!low[v]) {
tarjan(v, u);
Min(pre[u], pre[v]);
if(pre[v] >= low[u]) {
G[u].pb(++ndc);
for(int x = -1; x ^ v; )
G[ndc].pb(x = stk[tp--]);
}
}else Min(pre[u], low[v]);
}
}
void dfs(int u, int fa) {
if(u <= n) {
for(int i = 0; i < G[u].size(); ++i) dfs(G[u][i], u);
}else {
int res = 0;
for(int i = 0, len = G[u].size(); i < len; ++i) {
int v = G[u][i];
dfs(v, u);
Max(res, f[v][0] + min(i + 1, len - i));
}
if(res > f[fa][0]) {
f[fa][1] = f[fa][0];
f[fa][0] = res;
}else Max(f[fa][1], res);
}
}
int q[N], val[N];
int main() {
n = gi(), m = gi();ndc = n;
rep(i, 1, m) {
int k = gi(), lst = gi();
rep(j, 2, k) {
int x = gi();
Add(x, lst);
lst = x;
}
}
tarjan(1, 0);
dfs(1, 0);
rep(i, 1, n) Max(ans, f[i][0] + f[i][1]);
rep(i, n + 1, ndc) {
int gg = G[i].size();
G[i].pb(0);
for(int j = 0; j < gg; ++j) G[i].pb(G[i][j]);
int hd = 1, tl = 0, len = (gg + 1) / 2;
for(int j = 0; j < G[i].size(); ++j) {
if(j == gg) continue;
int x = G[i][j];
for(; hd <= tl && q[hd] < j - len; ++hd);
if(hd <= tl) Max(ans, f[x][0] + val[hd] + j);
for(; hd <= tl && f[x][0] - j >= val[tl]; --tl);
q[++tl] = j, val[tl] = f[x][0] - j;
}
}
printf("%d\n", ans);
return 0;
}

[SHOI2008]cactus仙人掌图[圆方树+树dp]的更多相关文章

  1. BZOJ1023:[SHOI2008]cactus仙人掌图(圆方树,DP,单调队列)

    Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus). 所谓简单回路就是指在图上不重复经过任何一个顶点 ...

  2. bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan缩环&&环上单调队列

    1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1141  Solved: 435[Submit][ ...

  3. bzoj千题计划113:bzoj1023: [SHOI2008]cactus仙人掌图

    http://www.lydsy.com/JudgeOnline/problem.php?id=1023 dp[x] 表示以x为端点的最长链 子节点与x不在同一个环上,那就是两条最长半链长度 子节点与 ...

  4. SHOI2008 cactus仙人掌图 和 UOJ87 mx的仙人掌

    cactus仙人掌图 题目描述 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一 ...

  5. 【BZOJ】1023: [SHOI2008]cactus仙人掌图 静态仙人掌(DFS树)

    [题意]给定仙人掌图(每条边至多在一个简单环上),求直径(最长的点对最短路径).n<=50000,m<=10^7. [算法]DFS树处理仙人掌 [题解]参考:仙人掌相关问题的处理方法(未完 ...

  6. [SHOI2008]cactus仙人掌图

    [题目描述] 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路. 举例 ...

  7. BZOJ1023: [SHOI2008]cactus仙人掌图(仙人掌)

    Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的 ...

  8. bzoj1023: [SHOI2008]cactus仙人掌图

    学习了一下圆方树. 圆方树是一种可以处理仙人掌的数据结构,具体见这里:http://immortalco.blog.uoj.ac/blog/1955 简单来讲它是这么做的:用tarjan找环,然后对每 ...

  9. 1023: [SHOI2008]cactus仙人掌图 - BZOJ

    Description如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路 ...

随机推荐

  1. Spring security实现国际化问题

    这两天Spring用户登录国际化这个问题困扰我好久啊,于昨天晚上终于把它干掉了. 场景就是我们公司的产品-incopat,需要支持中英文,用户登录这块用的spring自带的security,需求讲的通 ...

  2. 洗礼灵魂,修炼python(29)--装饰器(1)—>利用经典案例解析装饰器概念

    前提必备 不急着进入正题,在前面函数作用域那一章介绍了闭包,全局变量局部变量,这里再看几个简单的闭包案例: 1):不带参数 注意: 1.这里的name属性是每个函数都有的,可以反馈函数名 2.temp ...

  3. 洗礼灵魂,修炼python(17)--跨平台操作三剑客—os,os.path.sys模块

    os 1.作用: 因为客户基本都是使用不同的操作系统,在不同的系统下,要完成一个项目,那必须跨平台操作,而python本来就是一个跨平台的语言,而有了os模块,则不需要在意什么系统.并且os模块是用于 ...

  4. C#检测U盘是否插入

    public partial class Form1 : Form { #region u盘属性 public const int WM_DEVICECHANGE = 0x219;//U盘插入后,OS ...

  5. 用Python做股市数据分析(一)

    本文由 伯乐在线 - 小米云豆粥 翻译.未经许可,禁止转载!英文出处:Curtis Miller.欢迎加入翻译组. 这篇博文是用Python分析股市数据系列两部中的第一部,内容基于我犹他大学 数学39 ...

  6. ccf--20150303--节日

    本题思路:首先,计算a月1日是星期几,然后再通过b和c得出日期monday,最后判断monday是否合法. 题目与代码如下: 问题描述 试题编号: 201503-3 试题名称: 节日 时间限制: 1. ...

  7. Linux 小知识翻译 - 「内核(kernel)」

    上次介绍了Linus Torvalds, 这次介绍他开发的「内核」. 经常听人提到「Linux kernel」,但如果被问到「kernel究竟是什么?」的话,会出乎意料的觉得难以回答. 那么,kern ...

  8. Java的自动装箱和拆箱

    一.什么是装箱?什么是拆箱? 在前面的文章中提到,Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Jav ...

  9. [BJWC2011]元素

    嘟嘟嘟 题中说选的数的编号亦或和不能为0,也就是在这个集合中,不能用不同的选取方案亦或出相同的值.由此联想到线性基的一个性质是,每一个数都能由线性基中特定的一些数亦或得到. 所以我们就是要求出这些数的 ...

  10. Fermat vs. Pythagoras POJ - 1305 (数论之勾股数组(毕达哥拉斯三元组))

    题意:(a, b, c)为a2+b2=c2的一个解,那么求gcd(a, b, c)=1的组数,并且a<b<c<=n,和不为解中所含数字的个数,比如在n等于10时,为1, 2, 7,9 ...