Description

如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus)。

所谓简单回路就是指在图上不重复经过任何一个顶点的回路。

举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:

(4,3,2,1,6,5,4)、(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),

而(2,3)同时出现在前两个的简单回路里。另外,第三张图也不是仙人图,因为它并不是连通图。

显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。

定义在图上两点之间的距离为这两点之间最短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。

现在我们假定仙人图的每条边的权值都是1,你的任务是求出给定的仙人图的直径。

Input

输入的第一行包括两个整数n和m(1≤n≤50000以及0≤m≤10000)。其中n代表顶点个数,我们约定图中的顶点将从1到n编号。

接下来一共有m行。代表m条路径。每行的开始有一个整数k(2≤k≤1000),代表在这条路径上的顶点个数。

接下来是k个1到n之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两个顶点的边。

一条路径上可能通过一个顶点好几次,比如对于第一个样例,第一条路径从3经过8,又从8返回到了3,但是我们保证所有的边都会出现在某条路径上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。

Output

只需输出一个数,这个数表示仙人图的直径长度。

Sample Input

15 3
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
5 2 14 9 15 10 8
10 1
10 1 2 3 4 5 6 7 8 9 10

Sample Output

8
9

HINT

对第一个样例的说明:如图,6号点和12号点的最短路径长度为8,所以这张图的直径为8。

【注意】使用Pascal语言的选手请注意:你的程序在处理大数据的时候可能会出现栈溢出。
如果需要调整栈空间的大小,可以在程序的开头填加一句:{$M 5000000},其中5000000即
指代栈空间的大小,请根据自己的程序选择适当的数值。

Solution

如果只是求一颗树的直径的$DP$,应该是都会的,只需要记录一下$f[x]$表示从$x$点往下的最深深度就可以了。

现在把问题搬到仙人掌上,说道仙人掌就想到圆方树。今年下半年……

对于圆点,我们还是可以用$f$数组直接计算的。但是对于方点,相当于我们要求必须经过环的一颗基环树的直径。也就是求$f[i]+f[j]+dis(i,j)$的最大值,这个可以将环倍长用一个单调队列做。

稍微具体一点就是用单调队列维护最大值,若当前位置($i$)和队首($j$)距离超过$\frac{len}{2}$($len$为环长)时,就将队首弹出。因为会在后面的$i$(队首),$j+len$(当前位置)位置取到更优的值。

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define N (200009)
using namespace std; struct Edge{int to,next;}edge[N<<];
int n,m,bcc_num,ans,f[N],a[N],q[N];
int DFN[N],Low[N],dfs_num,stack[N],top;
int head[N],num_edge;
vector<int>E[N]; inline int read()
{
int x=,w=; char c=getchar();
while (c<'' || c>'') {if (c=='-') w=-; c=getchar();}
while (c>='' && c<='') x=x*+c-'', c=getchar();
return x*w;
} void add(int u,int v)
{
edge[++num_edge].to=v;
edge[num_edge].next=head[u];
head[u]=num_edge;
} void Tarjan(int x,int fa)
{
DFN[x]=Low[x]=++dfs_num; stack[++top]=x;
for (int i=head[x]; i; i=edge[i].next)
if (!DFN[edge[i].to])
{
Tarjan(edge[i].to,x);
if (Low[edge[i].to]>DFN[x]) E[x].push_back(edge[i].to), top--;
Low[x]=min(Low[x],Low[edge[i].to]);
if (Low[edge[i].to]==DFN[x])
{
E[x].push_back(++bcc_num);
while (top)
{
int now=stack[top--];
E[bcc_num].push_back(now);
if (now==edge[i].to) break;
}
}
}
else if (edge[i].to!=fa)
Low[x]=min(Low[x],DFN[edge[i].to]);
} void DFS(int x,int fa)
{
for (int i=; i<E[x].size(); ++i) DFS(E[x][i],x);
if (x<=n)
{
int cmax=;
for (int i=; i<E[x].size(); ++i)
{
cmax=max(cmax,f[E[x][i]]+);
if (cmax>f[x]) swap(f[x],cmax);
}
ans=max(ans,f[x]+cmax);
}
else
{
int l=,r=,cnt=;
for (int i=; i<E[x].size(); ++i) a[++cnt]=E[x][i];
for (int i=; i<=cnt; ++i) a[cnt+i]=a[i];
for (int i=; i<=cnt*; ++i)
{
while (l<=r && (i-q[l])>(cnt+)/) ++l;
if (i>=cnt) ans=max(ans,f[a[i]]+f[a[q[l]]]+i-q[l]);
while (l<=r && f[a[i]]-i>=f[a[q[r]]]-q[r]) r--;
q[++r]=i;
}
for (int i=; i<=cnt/; ++i) f[x]=max(f[x],f[a[i]]+i-);
for (int i=cnt/+; i<=cnt; ++i) f[x]=max(f[x],f[a[i]]+cnt-i);
}
} int main()
{
n=bcc_num=read(); m=read();
for (int i=; i<=m; ++i)
{
int k=read(),last=;
for (int j=; j<=k; ++j)
{
int x=read();
if (last) add(last,x), add(x,last);
last=x;
}
}
Tarjan(,);
DFS(,); printf("%d\n",ans);
}

BZOJ1023:[SHOI2008]cactus仙人掌图(圆方树,DP,单调队列)的更多相关文章

  1. [SHOI2008]cactus仙人掌图[圆方树+树dp]

    题意 求仙人掌的直径(相距最远的两个点的距离). \(n\le 5\times 10^4​\) 分析 建立圆方树,讨论答案路径的 lca 在圆点还是方点. 利用树形 dp 求出每个圆点到 不同子树内圆 ...

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

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

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

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

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

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

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

    Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3467  Solved: 1438[Submit][Status][Discuss] Descripti ...

  6. BZOJ1023[SHOI2008]cactus仙人掌图 【仙人掌DP】

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

  7. 2018.10.29 bzoj1023: [SHOI2008]cactus仙人掌图(仙人掌+单调队列优化dp)

    传送门 求仙人掌的直径. 感觉不是很难. 分点在环上面和不在环上分类讨论. 不在环上直接树形dpdpdp. 然后如果在环上讨论一波. 首先对环的祖先有贡献的只有环上dfsdfsdfs序最小的点. 对答 ...

  8. bzoj1023 [SHOI2008]cactus仙人掌图 & poj3567 Cactus Reloaded——求仙人掌直径

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1023    http://poj.org/problem?id=3567 仙人掌!直接模仿 ...

  9. [bzoj1023][SHOI2008]cactus 仙人掌图 (动态规划)

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

随机推荐

  1. xshell远程终端操作Ubuntu server安装LAMP环境之最详细笔记之二PHP开发环境配置

    前言: 昨天学会了安装server,今天试着通过远程终端xshell来安装LAMP,搭配一下开发环境,也有集成环境可以一键安装使用,还是瞎折腾一下,手动一步一步搭建一下这个开发环境. 接上一篇:ubu ...

  2. Java设计模式学习记录-GoF设计模式概述

    前言 最近要开始学习设计模式了,以前是偶尔会看看设计模式的书或是在网上翻到了某种设计模式,就顺便看看,也没有仔细的学习过.前段时间看完了JVM的知识,然后就想着JVM那么费劲的东西都看完了,说明自己学 ...

  3. 深入浅出 JVM GC(1)

    # 前言 初级 Java 程序员步入中级程序员的有一个无法绕过的阶段------GC(Garbage Collection).作为 Java 程序员,说实话,很幸福,不用像 C 程序员那样,时刻关心着 ...

  4. centos每天自动备份mysql数据库

    #!/bin/bash PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin export PATH #数据库用户名 db ...

  5. 分部类,分部方法 - 修饰符partial

    一.分部类 什么是部分类呢?简单来说就是将一个类型或方法拆分到两个或多个源文件中,每个源文件只包含类型定义的一部分. 当使用自动生成的源时,无须重新创建源文件便可将代码添加到类中.Visual Stu ...

  6. 浩顺考勤机二次开发(第二版,附实测可用的demo)

    1.背景 之前写过一次浩顺考勤机的二次开发,不过那个版本还是有一些问题,后来更换了新的考勤机,又拿到了新的二次开发包,所以就有了这次这个版本 2.关于考勤机的一些说明 2.1 首先要给考勤机设定ip, ...

  7. yapi部署文档

    windows 下 yapi部署文档 安装nodejs 安装mongodb 安装yapi 介绍 随着 web 技术的发展,前后端分离成为越来越多互联网公司构建应用的方式.前后端分离的优势是一套 Api ...

  8. DOM之城市二级联动

    1.HTML内容 <select id="province"> <option>请选择</option> <option>山东省&l ...

  9. prototype、proto和constructor的三角关系

    转载整理自http://www.cnblogs.com/xiaohuochai/p/5721552.html#3760057 http://blog.csdn.net/jasonzds/article ...

  10. Vue 爬坑之路(十二)—— vue-cli 3.x 搭建项目

    Vue Cli 3 官方文档:https://cli.vuejs.org/zh/guide/ 一.安装 @vue/cli 更新到 3.x 之后,vue-cli 的包名从 vue-cli 改成了 @vu ...