[BZOJ]1023 cactus仙人掌图(SHOI2008)
NOIP后的第一次更新嗯。
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。其中n代表顶点个数,我们约定图中的顶点将从1到n编号。接下来一共有m行。代表m条路径。每行的开始有一个整数k,代表在这条路径上的顶点个数。接下来是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
Sample Output
8
HINT
1≤n≤50000,0≤m≤10000,2≤k≤1000。
保证所有的边都会出现在某条路径上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。
如图,6号点和12号点的最短路径长度为8,所以这张图的直径为8。

Solution
关于业界毒瘤仙人掌的初探。
毕竟仙人掌的原型还是树,所以我们想办法把仙人掌转化成树来做。
最直接的想法是缩环,变成树形DP,然后自己在环内瞎搞搞来更新答案。
事实证明,这种方法是可行的。例如样例,我们可以通过缩点的方式把仙人掌转化成如下的树:

这样树上的每一个点都是一个环,环与环之间根据原图的构造连上0或1的边,这是最简单最无脑的建图方式。
现在我们考虑怎么在环内瞎搞:

假设一个这样的环,其中环上一些节点有通向儿子的边,红色节点上有通向父亲的边。
考虑最普通的树上DP求直径,我们很自然地对于每个环维护所有后辈中,距离红色节点最远的点的距离,以便向上更新答案。
这样我们就知道了这个环上所有拥有通向儿子的边的节点离它的所有后辈的最远距离,这样直接加上在环上离红色节点的距离就可以更新DP值。
当然,这个环上没有拥有通向儿子的边的节点也可以更新DP值,注意一下即可。
但是按照树形DP求直径,以该点为lca的直径是最大的两个儿子的DP值之和。如果放在一个环上该怎么求呢?
这个做法同样很经典,对于环,我们一般的做法是拆环成链,再把链复制一份接到后面来做,例如旋转卡壳的做法。
所以对于这个问题,我们同样只要把被拆环之后的链扫一遍,用单调队列维护每个点之前的最大值来更新就好了。
这也大概就是最笨的算法的整个流程。
缩环建图虽然简单,但写起来确实复杂。但基于以上思想,我们依然可以对代码进行优化。
在缩环建图的时候,我们实际上已经找出了仙人掌图的dfs树,然后对于每条返祖边,我们建立一个环。
这条返祖边是名副其实的返祖边,一定会返回到该点的祖先。也就是说,图中的环一定对应的是dfs树上一条由上到下的链。

而且根据仙人掌图的性质,这些链不会相交。
再仔细想想,这些链中深度最小的点,不就是我们刚刚所说的环内的红色节点么?
所以我们在对一个环进行DP的时候,只要把得到的信息丢到环中深度最小的点里就可以了。
然后对于非环边x→y(也就是图中的桥),直接更新f[x]=max(f[x],f[y]+1)即可。
还有就是处理顺序的问题。例如样例,我们在遍历到10号节点后,必须先往11号节点走而不是15号节点。
因为在15号节点对于9号节点的更新有赖于13号节点对10号节点的更新。
剩下就是代码实现的问题了。这样的代码会比之前介绍的的方法简洁很多。
时间复杂度O(n+mk)。第一种方法写得太丑就不发了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MN 100005
#define MM 5000005
using namespace std;
struct edge{int nex,to;}e[MM];
bool u[MN],ih[MN];
int hr[MN],dep[MN],lto[MN],dw[MN],bac[MN],f[MN],sk[MN],q[MN];
int pin,tp,hd,tl,ans,n,m,p,pre; inline int read()
{
int n=,f=; char c=getchar();
while (c<'' || c>'') {if(c=='-')f=-; c=getchar();}
while (c>='' && c<='') {n=n*+c-''; c=getchar();}
return n*f;
} inline void ins(int x,int y) {e[++pin]=(edge){hr[x],y}; hr[x]=pin;}
inline int dis(int x,int y) {return x<=y/?x:y-x;} void dp(int x,int depth)
{
register int i;
u[x]=true; dw[depth]=x;
for (i=hr[x];i;i=e[i].nex)
{
if (u[e[i].to]||e[i].to==lto[x]) continue;
dp(e[i].to,depth+);
if (!ih[e[i].to]) ans=max(ans,f[x]+f[e[i].to]+),f[x]=max(f[x],f[e[i].to]+);
}
if (lto[x]) dp(lto[x],depth+);
if (bac[x])
{
tp=;
for (i=dep[bac[x]];i<=dep[x];++i) sk[tp++]=f[dw[i]];
for (i=;i<tp;++i) sk[tp+i]=sk[i];
tp<<=; hd=; tl=;
for (i=;i<tp;++i)
{
if (i<(tp>>)) f[bac[x]]=max(f[bac[x]],sk[i]+dis(i,tp>>));
for (;hd<=tl&&i-q[hd]>(tp>>);++hd);
if (hd<=tl) ans=max(ans,sk[i]+sk[q[hd]]+i-q[hd]);
for (;hd<=tl&&sk[i]-i>=sk[q[tl]]-q[tl];--tl);
q[++tl]=i;
}
}
ans=max(ans,f[x]);
} void dfs(int x,int fat,int depth)
{
register int i,j;
u[x]=true; dep[x]=depth; dw[depth]=x;
for (i=hr[x];i;i=e[i].nex)
{
if ((i^)==fat) continue;
if (u[e[i].to])
{
for (j=dep[e[i].to]+;j<dep[x];++j) lto[dw[j]]=dw[j+];
for (j=dep[e[i].to]+;j<=dep[x];++j) ih[dw[j]]=true;
if (dep[x]>dep[e[i].to]) bac[x]=e[i].to;
}
else dfs(e[i].to,i,depth+);
}
} int main()
{
register int x,i;
n=read(); m=read(); pin=;
while (m--)
for (p=read()-,pre=read();p;--p)
x=read(),ins(x,pre),ins(pre,x),pre=x;
memset(u,,sizeof(u)); dfs(,,);
memset(u,,sizeof(u)); dp(,);
printf("%d\n",ans);
}
Last Word
顺带一提,基环外向树也是通过把环取出来转化成树上问题的,而基环外向树也是一种特殊的仙人掌。
基环外向树在BZOJ第一页同样有一道裸题:BZOJ1040。
所以仙人掌什么的大概就是这种模型了吗?
[BZOJ]1023 cactus仙人掌图(SHOI2008)的更多相关文章
- 【BZOJ】【1023】【SHOI2008】cactus仙人掌图
DP+单调队列/仙人掌 题解:http://hzwer.com/4645.html->http://z55250825.blog.163.com/blog/static/150230809201 ...
- bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan缩环&&环上单调队列
1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1141 Solved: 435[Submit][ ...
- bzoj千题计划113:bzoj1023: [SHOI2008]cactus仙人掌图
http://www.lydsy.com/JudgeOnline/problem.php?id=1023 dp[x] 表示以x为端点的最长链 子节点与x不在同一个环上,那就是两条最长半链长度 子节点与 ...
- SHOI2008 cactus仙人掌图 和 UOJ87 mx的仙人掌
cactus仙人掌图 题目描述 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一 ...
- 1023: [SHOI2008]cactus仙人掌图 - BZOJ
Description如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路 ...
- 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图
Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的 ...
- 【BZOJ】1023: [SHOI2008]cactus仙人掌图 静态仙人掌(DFS树)
[题意]给定仙人掌图(每条边至多在一个简单环上),求直径(最长的点对最短路径).n<=50000,m<=10^7. [算法]DFS树处理仙人掌 [题解]参考:仙人掌相关问题的处理方法(未完 ...
- bzoj 1023: [SHOI2008]cactus仙人掌图 2125: 最短路 4728: 挪威的森林 静态仙人掌上路径长度的维护系列
%%% http://immortalco.blog.uoj.ac/blog/1955 一个通用的写法是建树,对每个环建一个新点,去掉环上的边,原先环上每个点到新点连边,边权为点到环根的最短/长路长度 ...
- 1023: [SHOI2008]cactus仙人掌图(DP+单调队列优化)
这道题吗= =首先解决了我多年以来对仙人掌图的疑问,原来这种高大上的东西原来是这个啊= = 然后,看到这种题,首先必须的就是缩点= = 缩点完之后呢,变成在树上找最长路了= =直接树形dp了 那么那些 ...
随机推荐
- C++数据结构中的基本算法排序
冒泡排序 基本思想:两两比较待排序的数,发现反序时交换,直到没有反序为止. public static void BubbleSort(int[] R) { for (int i = 0; i < ...
- android数据库持久化框架, ormlite框架,
前言 Android中内置了SQLite,但是对于数据库操作这块,非常的麻烦.其实可以试用第3方的数据库持久化框架对之进行结构上调整, 摆脱了访问数据库操作的细节,不用再去写复杂的SQL语句.虽然这样 ...
- JAVA中if多分支和switch的优劣性。
Switch多分支语句switch语句是多分支选择语句.常用来根据表达式的值选择要执行的语句.例如,在某程序中,要求将输入的或是获取的用0-6代表的星期,转换为用中文表示的星期.该需求通过伪代码描述的 ...
- 坑爹了多少年的html元素垂直居中问题
原文章:https://www.w3cplus.com/css3/a-guide-to-flexbox.html 如果你的元素有固定高度的话 父元素用display: flex;height:100p ...
- 根据HTML5的新方法 drag & drop 方法实现表格拖拽实例
上一次学习了html5的drag和drop方法,传送门 就自己写了个例子加深自己对drag和drop的理解.不过一开始不是很简单,遇到了不少问题.还好网络万能的,什么都能查到,总算完成了. 说明和详 ...
- Postgres中postmaster代码解析(上)
之前我的一些文章都是在说Postgres的一些查询相关的代码.但是对于Postgres服务端是如何启动,后台进程是如何加载,服务端在哪里以及如何监听客户端的连接都没有一个清晰的逻辑.那么今天我来说说P ...
- 算法题丨Move Zeroes
描述 Given an array nums, write a function to move all 0's to the end of it while maintaining the rela ...
- MQTT和paho(一)
参考链接:http://blog.csdn.net/yangzl2008/article/details/8861069 一.mqtt 1.简单介绍 http://mqtt.org/software ...
- SpringBoot应用的前台目录
一.两个重要目录 templates:存放web页面的模板文件,需要在controller返回视图名称,框架转发才能找到的html. static :存放静态资源,如:html(放在这里可直接访问,如 ...
- Angular 学习笔记 (路由外传 - RouteReuseStrategy)
refer : https://github.com/angular/angular/issues/10929 https://stackoverflow.com/questions/41280471 ...