Solution

好题啊没的说。

本题需要求出仙人掌的直径,但仙人掌是一个带有简单环的一张图无法直接用树形dp求解,但它有一个好东西就是没有类似环套环的东西,所以我们在处理时就方便了一些。

思路:tarjan找环,对于不在环上的边或点,树形dp求解,对于每个环,dp求解(单调队列优化),

下面主要说一下代码的实现,

void tarjan(int u,int ff)
{
dfn[u]=low[u]=++top;
deep[u]=deep[ff]+;
for(int i=head[u];i;i=an[i].n)
if(an[i].to!=ff)
{
int v=an[i].to;
if(!dfn[v])
{
fa[v]=u;
tarjan(v,u);
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[v]+,f[u]);
}
}
for(int i=head[u];i;i=an[i].n)
if(an[i].to!=ff&&fa[an[i].to]!=u&&dfn[an[i].to]>dfn[u])
ddpp(u,an[i].to);
}

这里是tarjan找环的部分,和普通的tarjan不一样的是,由于我们不用缩点并且仙人掌图没有横叉边,所以并不用开栈存点,当dfn[u]<low[v]时,说明这条边不在环上,可以用树形dp,下面用来判断当u
是环上一点并且是环上点中dfn序最小的点,这是就可以进行dp了(这是为了重)。

inline void ddpp(int s,int t)
{
int len=deep[t]-deep[s]+,te=len;
for(int i=t;i!=s;i=fa[i])
c[te--]=i;
c[]=s;
for(int i=;i<=len;++i)
c[i+len]=c[i];
int h=t=;q[h]=;
for(int i=;i<=len*;++i)
{
while(h<=t&&(i-q[h])>len/)h++;
if(h<=t)ans=max(ans,f[c[q[h]]]+f[c[i]]+i-q[h]);
while(h<=t&&f[c[q[t]]]-q[t]<=f[c[i]]-i)t--;
q[++t]=i;
}
for(int i=;i<=len;++i)
f[s]=max(f[s],f[c[i]]+min(len-i+,i-));
}

单调队列优化dp,用到了断环成链的技巧,要注意dp结束后要用环上所有点来更新s点,因为除了s点外其他点以后都没有用了,但s点还要向上更新,这步操作相当于把环缩成一个点。

完整代码

#include<iostream>
#include<cstdio>
#define N 50009
#define M 2000009
using namespace std;
int dfn[N],low[N],ans,deep[N],c[N<<],q[N<<],f[N],tot,head[N],top,fa[N],u,v,n,m,k;
struct ef
{
int n,to;
}an[M];
inline void add(int u,int v)
{
an[++tot].n=head[u];
an[tot].to=v;
head[u]=tot;
}
inline void ddpp(int s,int t)
{
int len=deep[t]-deep[s]+,te=len;
for(int i=t;i!=s;i=fa[i])
c[te--]=i;
c[]=s;
for(int i=;i<=len;++i)
c[i+len]=c[i];
int h=t=;q[h]=;
for(int i=;i<=len*;++i)
{
while(h<=t&&(i-q[h])>len/)h++;
if(h<=t)ans=max(ans,f[c[q[h]]]+f[c[i]]+i-q[h]);
while(h<=t&&f[c[q[t]]]-q[t]<=f[c[i]]-i)t--;
q[++t]=i;
}
for(int i=;i<=len;++i)
f[s]=max(f[s],f[c[i]]+min(len-i+,i-));
}
void tarjan(int u,int ff)
{
dfn[u]=low[u]=++top;
deep[u]=deep[ff]+;
for(int i=head[u];i;i=an[i].n)
if(an[i].to!=ff)
{
int v=an[i].to;
if(!dfn[v])
{
fa[v]=u;
tarjan(v,u);
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[v]+,f[u]);
}
}
for(int i=head[u];i;i=an[i].n)
if(an[i].to!=ff&&fa[an[i].to]!=u&&dfn[an[i].to]>dfn[u])
ddpp(u,an[i].to);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;++i)
{
scanf("%d%d",&k,&u);
for(int j=;j<k;++j)
{
scanf("%d",&v);
add(u,v),add(v,u);
u=v;
}
}
tarjan(,);
cout<<ans;
return ;
}

SHOI2008仙人掌图(tarjan+dp)的更多相关文章

  1. 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告

    P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...

  2. [SHOI2008]仙人掌图

    [SHOI2008]仙人掌图 LG传送门 还不会仙人掌的同学可以看看我对仙人掌知识的一些梳理. 题意就是求仙人掌的直径,直径定义为图中最短路径最长的两点间的最短路径长度. 按照套路,先考虑求树的直径我 ...

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

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

  4. BZOJ1023:[SHOI2008]仙人掌图——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1023 Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple ...

  5. [SHOI2008]仙人掌图 II——树形dp与环形处理

    题意: 给定一个仙人掌,边权为1 距离定义为两个点之间的最短路径 直径定义为距离最远的两个点的距离 求仙人掌直径 题解: 类比树形dp求直径. f[i]表示i向下最多多长 处理链的话,直接dp即可. ...

  6. Luogu 4244 [SHOI2008]仙人掌图

    BZOJ 1023 如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径. 设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f ...

  7. P4244 [SHOI2008]仙人掌图 II

    传送门 仙人掌直径,以前好像模拟赛的时候做到过一道基环树的直径,打了个很麻烦的然而还错了--今天才发现那就是这个的弱化版啊-- 如果是树的话用普通的dp即可,记\(f[u]\)表示\(u\)往下最长能 ...

  8. BZOJ1023 SHOI2008 仙人掌图 仙人掌、单调队列

    传送门 求仙人掌的直径,可以由求树的直径进行拓展,只需要在环上特殊判断. 沿用求树的直径的DP,对于一条不在任何环内的边,直接像树的直径一样转移,然后考虑环的影响. 设环长为\(cir\),在\(df ...

  9. 【题解】SHOI2008仙人掌图

    本质上还是树形dp.建立圆方树,遇到圆点的时候直接求(和树形dp一样即可),遇到方点做中转点的时候要考虑会从圆的另一侧通过(需满足最短路径的原则).原本是对于圆上的点进行 \(n^{2}\) 的匹配, ...

随机推荐

  1. jvisualvm远程监控 visualgc插件 不受此jvm支持问题

    https://yq.aliyun.com/ziliao/478212 1.修改远程服务器上java设置 vi $JAVA_HOME/jre/lib/security/java.policy    在 ...

  2. linux命令:拷贝命令家族(cp、scp、rsync)

    Linux命令中:rsync和cp之间的区别 - 小 楼 一 夜 听 春 雨 - 博客园https://www.cnblogs.com/kex1n/p/7008178.html cp,scp,rsyn ...

  3. java的static与C#的static的异同

    static static同样可以用在类.方法.变量上面,但是在java和C#中所表示的意思完全不同,我个人的总结是C#中的静态和非静态是有一个明显的分界的,静态的是属于类级别的,而非静态的是属于实例 ...

  4. HDU 2459 Maximum repetition substring

    题目:Maximum repetition substring 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2459 题意:给你一个字符串,求连续重复出现 ...

  5. 转《service worker在移动端H5项目的应用》

    1. PWA和Service Worker的关系 PWA (Progressive Web Apps) 不是一项技术,也不是一个框架,我们可以把她理解为一种模式,一种通过应用一些技术将 Web App ...

  6. DNS 到底怎么工作的? (How does dns work?)

    其实这个问题每次看的时候都觉得很明白,但是很久之后就忘记了,所以这次准备记录下来.深入到这个过程的各个细节之中,以后多看看. Step 1 请求缓存信息: 当你在开始访问一个 www.baidu.co ...

  7. Service Account和RBAC授权

    一.介绍 Service Account概念的引入是基于这样的使用场景:运行在pod里的进程需要调用Kubernetes API以及非Kubernetes API的其它服务.Service Accou ...

  8. 莫烦keras学习自修第五天【CNN卷积神经网络】

    1.代码实战 #!/usr/bin/env python #! _*_ coding:UTF-8 _*_ import numpy as np np.random.seed(1337) # for r ...

  9. 关于PHP函数传参的注意点

    PHP的实参在传递过程中是顺序传递的,不支持指定参数名传递.怎么理解呢?看下面的代码: function test($name,$age){ echo '姓名:'.$name,' 年纪:'.$age; ...

  10. DBC格式解析(数据部分)

    dbc格式说明:DBC Format   实战: 我们先来看一段数据 BO_ VOLTAGE01: BMS2 SG_ V01 : |@+ () [|] "" Vector__XXX ...