BZOJ1023:[SHOI2008]仙人掌图——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1023
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
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 2 3 4 5 6 7 8 9 10
Sample Output
9
——————————————————————————
看hzwer的博客吧:http://hzwer.com/4645.html
(以及虽然我知道怎么做了但是不会单调队列的我决定什么时候会了单调队列什么时候再补题解)
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=;
const int M=;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int to;
int nxt;
}edge[M];
int head[N],val[N],num[N],cnt=;
int n,m,low[N],dfn[N],fa[N],t=;
int ans=,dep[N],f[N],a[N*];
int q[N*],l,r;
bool vis[N];
inline void add(int u,int v){
cnt++;
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
return;
}
void dp(int rt,int u){
int delta=dep[u]-dep[rt]+;
for(int i=u;i!=rt;i=fa[i])a[delta--]=f[i];
a[delta]=f[rt];
delta=dep[u]-dep[rt]+;
for(int i=;i<=delta;i++)a[i+delta]=a[i];
q[]=;l=r=;
for(int i=;i<=*delta;i++){
while(l<=r&&i-q[l]>delta/)l++;
ans=max(ans,a[i]+i+a[q[l]]-q[l]);
while(l<=r&&a[q[r]]-q[r]<=a[i]-i)r--;
q[++r]=i;
}
for(int i=;i<=delta;i++){
f[rt]=max(f[rt],a[i]+min(i-,delta-i+));
}
return;
}
void tarjan(int u){
dfn[u]=low[u]=++t;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u])continue;
if(!dfn[v]){
fa[v]=u;
dep[v]=dep[u]+;
tarjan(v);
low[u]=min(low[u],low[v]);
}else{
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]<low[v]){//桥
ans=max(ans,f[u]+f[v]+);
f[u]=max(f[u],f[v]+);
}
}
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(fa[v]!=u&&dfn[u]<dfn[v]){//环
dp(u,v);
}
}
return;
}
int main(){
n=read();m=read();
for(int i=;i<=m;i++){
int k=read(),u=read();
for(int j=;j<=k;j++){
int v=read();
add(u,v);add(v,u);
u=v;
}
}
tarjan();
printf("%d\n",ans);
return ;
}
BZOJ1023:[SHOI2008]仙人掌图——题解的更多相关文章
- BZOJ1023 SHOI2008 仙人掌图 仙人掌、单调队列
传送门 求仙人掌的直径,可以由求树的直径进行拓展,只需要在环上特殊判断. 沿用求树的直径的DP,对于一条不在任何环内的边,直接像树的直径一样转移,然后考虑环的影响. 设环长为\(cir\),在\(df ...
- 【BZOJ1023】仙人掌图(仙人掌,动态规划)
[BZOJ1023]仙人掌图(仙人掌,动态规划) 题面 BZOJ 求仙人掌的直径(两点之间最短路径最大值) 题解 一开始看错题了,以为是求仙人掌中的最长路径... 后来发现看错题了一下就改过来了.. ...
- 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告
P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...
- 【bzoj1023】仙人掌图
[bzoj1023]仙人掌图 题意 给一棵仙人掌,求直径. \(n\leq 100000\) 分析 分析1:[Tarjan]+[环处理+单调队列优化线性dp]+[树形dp] 分开两种情况处理: ①环: ...
- [SHOI2008]仙人掌图
[SHOI2008]仙人掌图 LG传送门 还不会仙人掌的同学可以看看我对仙人掌知识的一些梳理. 题意就是求仙人掌的直径,直径定义为图中最短路径最长的两点间的最短路径长度. 按照套路,先考虑求树的直径我 ...
- [SHOI2008]仙人掌图 II——树形dp与环形处理
题意: 给定一个仙人掌,边权为1 距离定义为两个点之间的最短路径 直径定义为距离最远的两个点的距离 求仙人掌直径 题解: 类比树形dp求直径. f[i]表示i向下最多多长 处理链的话,直接dp即可. ...
- SHOI2008仙人掌图(tarjan+dp)
Solution 好题啊没的说. 本题需要求出仙人掌的直径,但仙人掌是一个带有简单环的一张图无法直接用树形dp求解,但它有一个好东西就是没有类似环套环的东西,所以我们在处理时就方便了一些. 思路:ta ...
- 【题解】SHOI2008仙人掌图
本质上还是树形dp.建立圆方树,遇到圆点的时候直接求(和树形dp一样即可),遇到方点做中转点的时候要考虑会从圆的另一侧通过(需满足最短路径的原则).原本是对于圆上的点进行 \(n^{2}\) 的匹配, ...
- Luogu 4244 [SHOI2008]仙人掌图
BZOJ 1023 如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径. 设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f ...
随机推荐
- Unity Shader学习笔记 - 用UV动画实现沙滩上的泡沫
这个泡沫效果来自远古时代的Unity官方海岛Demo, 原效果直接复制3个材质球在js脚本中做UV动画偏移,这里尝试在shader中做动画并且一个pass中完成: // Upgrade NOTE: r ...
- JavaScript基本概念(1)-声明提升
声明提升: function > var > other var提升的时候,只是声明提升,但是赋值还是会在原来的位置. Javascript Hoisting:In javascript, ...
- leetcode-位1的个数(位与运算)
位1的个数 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量). 示例 : 输入: 11 输出: 3 解释: 整数 11 的二进制表示为 00000 ...
- Visaul Studio 密钥
vs professional 2015 简体中文版 :HMGNV-WCYXV-X7G9W-YCX63-B98R2
- UVa 340 - Master-Mind Hints 解题报告 - C语言
1.题目大意 比较给定序列和用户猜想的序列,统计有多少数字位置正确(x),有多少数字在两个序列中都出现过(y)但位置不对. 2.思路 这题自己思考的思路跟书上给的思路差不多.第一个小问题——位置正确的 ...
- 深入理解eos账户体系 active和action
在eos中,账户是一个非常重要的概念. 账户分为两部分组成 一种是active 一种是action. 智能合约本质上来讲就是一个action加上一个回馈脚本程序.任何智能合约都有这俩个部分组成. 那么 ...
- ssh连接失败, 记下来原因和解决方案
mac下使用secureCRT发现连接不了虚拟机上的linux 运行 ps -e | grep ssh,查看是否有sshd进程 如果没有,说明server没启动,通过 /etc/init.d/sshd ...
- File Searching
Description Have you ever used file searching tools provided by an operating system? For example, in ...
- java设计模式简介
设计模式简介: 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用.设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案.这些解决方案是众多 ...
- 《剑指offer》---输出链表倒数第k个结点
本文算法使用python3实现 1 题目描述: 输入一个链表,输出该链表中倒数第k个结点. 时间限制:1s:空间限制:32768K 2 思路描述: 方法一:当链表长度为 $ n $ 时,输 ...