BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)
类似求树的直径,可以用(类似)树形DP求每个点其子树(在仙人掌上就是诱导子图)最长链、次长链,用每个点子节点不同子树的 max{最长链}+max{次长链} 更新答案。(不需要存次长链,求解过程中先更新ans,然后再更新最长链即可)
设f[i]为点i的诱导子图中最长链的长度。
对于环,我们找一个环上dep[]最小的点x代表这个环 看做一个点(dep为按DFS顺序更新的),求出f[x],环以外的部分像树一样直接做就可以。
对于环的处理:f[x]比较显然,f[x]=max{f[v]+dis(x,v)},v为其环上一点,dis(x,v)为x,v在环上的最小距离。
环上如何更新答案?把环上所有点都拿出来,ans=max{f[u]+f[v]+dis(u,v)}。
u,v是环上的点,按顺序编号,dis(u,v)=v-u(v-u<=len/2),那么ans可以写成 max{f[u]-u+f[v]+v}。固定v,因为u是单增的,所以之前最大的f[u]-u在后面也是最大的,可以用单调队列维护。
dis()是环上最小距离,所以v-u不能超过 环长/2。因为是个环,所以把它拆成一个3/2*len的序列更新ans。
之后用f[v]+dis(x,v)更新f[x]。
扫一遍所有的环,总共复杂度是\(O(m)\)。
总:Tarjan,对于不在同一环上的点,用f[x]+f[v]+1更新ans,再用f[v]更新f[x];对于其它的点,像上面那样取出环单调队列处理。
//8760kb 192ms
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=5e4+5,M=N<<2;//边数。。大概最多2n条?
int n,m,Ans,Enum,H[N],to[M],nxt[M],dfn[N],low[N],id,fa[N],dep[N],f[N],q[N],A[N<<1];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AddEdge(int u,int v){
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void DP(int x,int ed)
{
int n=dep[ed]-dep[x]+1;//length
for(int i=n; i; --i) A[i]=f[ed], ed=fa[ed];
int n2=n+(n>>1);//能同时更新别的的最多只有n/2个点,所以只需要3/2*n
for(int i=n+1; i<=n2; ++i) A[i]=A[i-n];
int h=1,t=1; q[1]=1;
for(int i=2; i<=n2; ++i)//i,q[]是点,拿出来的A[]是f[]!
{
while(h<t && i-q[h]>(n>>1)) ++h;
Ans=std::max(Ans,A[q[h]]-q[h]+A[i]+i);
while(h<=t && A[q[t]]-q[t]<=A[i]-i) --t;//注意这个比较是<,因为更新队首时不是根据值的大小,而是限制条件(<=竟然有90...)
q[++t]=i;
}
for(int i=2; i<=n; ++i)
f[x]=std::max(f[x],A[i]+std::min(i-1,n-i+1));
}
void DFS(int x)
{
dfn[x]=low[x]=++id;
for(int v,i=H[x]; i; i=nxt[i])
if((v=to[i])!=fa[x])
{
if(!dfn[v])
fa[v]=x, dep[v]=dep[x]+1, DFS(v), low[x]=std::min(low[x],low[v]);
if(low[v]>dfn[x])//不是环
Ans=std::max(Ans,f[x]+f[v]+1), f[x]=std::max(f[x],f[v]+1);
low[x]=std::min(low[x],dfn[v]);//无向图,就不需要什么在栈中了 //只需判环,所以和下一行写法一样
// low[x]=std::min(low[x],low[v]);
}
for(int i=H[x]; i; i=nxt[i])
if(fa[to[i]]!=x&&dfn[to[i]]>dfn[x]) DP(x,to[i]);//找环的另一个端点
//端点是后访问的点,而不只是&&to[i]!=fa[x]!(当x同时在两个环上时)能找到之前的环和x之后的环,但x不代表(没必要)之前访问的环,这样找环还麻烦。。不是沿to[i]的fa到x。
}
int main()
{
n=read(),m=read();
int num,u,v;
while(m--){
num=read()-1, u=read();
while(num--) v=read(),AddEdge(u,v),u=v;
}
DFS(1);
printf("%d",Ans);
return 0;
}
BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)的更多相关文章
- bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan缩环&&环上单调队列
1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1141 Solved: 435[Submit][ ...
- 1023: [SHOI2008]cactus仙人掌图(DP+单调队列优化)
这道题吗= =首先解决了我多年以来对仙人掌图的疑问,原来这种高大上的东西原来是这个啊= = 然后,看到这种题,首先必须的就是缩点= = 缩点完之后呢,变成在树上找最长路了= =直接树形dp了 那么那些 ...
- 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图
Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的 ...
- BZOJ 1023: [SHOI2008]cactus仙人掌图 | 在仙人掌上跑DP
题目: 求仙人掌直径 http://www.lydsy.com/JudgeOnline/problem.php?id=1023 题解: 首先给出仙人掌的定义:满足所有的边至多在一个环上的无向联通图 我 ...
- bzoj 1023: [SHOI2008]cactus仙人掌图【tarjan+dp+单调队列】
本来想先求出点双再一个一个处理结果写了很长发现太麻烦 设f[u]为u点向下的最长链 就是再tarjan的过程中,先照常处理,用最长儿子链和次长儿子链更新按ans,然后处理以这个点为根的环,也就是这个点 ...
- bzoj 1023: [SHOI2008]cactus仙人掌图 2125: 最短路 4728: 挪威的森林 静态仙人掌上路径长度的维护系列
%%% http://immortalco.blog.uoj.ac/blog/1955 一个通用的写法是建树,对每个环建一个新点,去掉环上的边,原先环上每个点到新点连边,边权为点到环根的最短/长路长度 ...
- bzoj 1023 [SHOI2008]cactus仙人掌图 ( poj 3567 Cactus Reloaded )——仙人掌直径模板
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1023 http://poj.org/problem?id=3567 因为lyd在讲课,所以有 ...
- bzoj 1023: [SHOI2008]cactus仙人掌图
这道题是我做的第一道仙人掌DP,小小纪念一下…… 仙人掌DP就是环上的点环状DP,树上的点树上DP.就是说,做一遍DFS,DFS的过程中处理出环,环上的点先不DP,先把这些换上的点的后继点都处理出来, ...
- 1023: [SHOI2008]cactus仙人掌图 - BZOJ
Description如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路 ...
随机推荐
- IOS的属性和实例变量
实际上,@property声明的是属性,并不是实例变量.但是编译器会根据属性,自动生成实例变量,和对应的access方法.所以已经在interface里声明了@property,就不再需要在imple ...
- MyBatis中传入参数parameterType类型详解
前言 Mybatis的Mapper文件中的select.insert.update.delete元素中有一个parameterType属性,用于对应的mapper接口方法接受的参数类型.本文主要给大家 ...
- bzoj千题计划269:bzoj2655: calc (拉格朗日插值)
http://www.lydsy.com/JudgeOnline/problem.php?id=2655 f[i][j] 表示[1,i]里选严格递增的j个数,序列值之和 那么ans=f[A][n] * ...
- poj 3686 Priest John's Busiest Day
http://poj.org/problem?id=3683 2-sat 问题判定,输出一组可行解 http://www.cnblogs.com/TheRoadToTheGold/p/8436948. ...
- bzoj千题计划199:bzoj1055: [HAOI2008]玩具取名
http://www.lydsy.com/JudgeOnline/problem.php?id=1055 区间DP dp[i][j][k] 表示区间[i,j]能否合成k #include<cst ...
- bzoj千题计划186:bzoj1048: [HAOI2007]分割矩阵
http://www.lydsy.com/JudgeOnline/problem.php?id=1048 #include<cmath> #include<cstdio> #i ...
- Java入门系列(八)多线程
基本线程类指的是Thread类,Runnable接口,Callable接口 典型多线程问题 生产者-消费者 死锁问题
- 基础知识点 关于 prototype __proto__
基础知识点 关于 prototype __proto__ 供js新手参考 JavaScript 的一些基础知识点: 在 JavaScript 中,所有对象 o 都拥有一个隐藏的原型对象(在 Fire ...
- iOS常用小功能
CHENYILONG Blog 常用小功能 技术博客http://www.cnblogs.com/ChenYilong/ 新浪微博http://weibo.com/luohanchenyilong ...
- WIN10文件无法自动刷新问题解决方法
Window10系统有时候会遇到以下类似的问题 1.文件删除后,图标还在,无法自动刷新屏幕,按F5或右键菜单刷新后才消失 2.文件粘贴后,不显示,刷新后才显示 3.回收站清理后,文件图标仍显示有垃圾 ...