%%% http://immortalco.blog.uoj.ac/blog/1955

一个通用的写法是建树,对每个环建一个新点,去掉环上的边,原先环上每个点到新点连边,边权为点到环根的最短/长路长度

1023 求仙人掌直径

树形dp,维护每个点向下的最长和次长路径长度,对原有的点直接更新答案,对新点可以把对应环上的点取出,倍长,破环成链,并用单调队列正反各扫一次

#include<cstdio>
char buf[],*ptr=buf-;
int _(){
int x=,c=*++ptr;
while(c<)c=*++ptr;
while(c>)x=x*+c-,c=*++ptr;
return x;
}
const int N=;
int es[N],enx[N],ev[N],e0[N],e1[N],ep=;
int dfn[N],low[N],tk=,ss[N],sp=,os[N],op,q[N],ql,qr;
int n,m,D,idp,ans=,f1[N],f2[N];
void ae(int*e,int a,int b,int c){
es[ep]=b;enx[ep]=e[a];ev[ep]=c;e[a]=ep++;
es[ep]=a;enx[ep]=e[b];ev[ep]=c;e[b]=ep++;
}
int min(int a,int b){return a<b?a:b;}
void maxs(int&a,int b){if(a<b)a=b;}
void maxs(int&a,int&b,int c){
if(a<=c)b=a,a=c;
else if(b<c)b=c;
}
void tj(int w){
dfn[w]=low[w]=++tk;
for(int i=e0[w];i;i=enx[i]){
int u=es[i];
if(!u)continue;
es[i^]=;
if(!dfn[u]){
ss[++sp]=u;
tj(u);
if(ss[sp]==u)--sp,ae(e1,w,u,);
}else if((low[w]=min(low[w],dfn[u]))==dfn[u]){
op=;
while(sp&&dfn[ss[sp]]>dfn[u])os[++op]=ss[sp--];
ae(e1,u,++idp,);
for(int j=;j<=op;++j)ae(e1,idp,os[j],min(j,op+-j));
}
}
}
void dfs(int w,int pa){
for(int i=e1[w];i;i=enx[i]){
int u=es[i];
if(u==pa)continue;
dfs(u,w);
maxs(f1[w],f2[w],f1[u]+ev[i]);
}
if(w<=n)maxs(ans,f1[w]+f2[w]);
else{
op=;
for(int i=e1[w];i;i=enx[i]){
int u=es[i];
if(u!=pa)os[++op]=u;
}
os[++op]=pa;
D=op>>;
ql=,qr=;
for(int i=;i<=D;++i)os[op+i]=os[i];
op+=D;
for(int i=;i<=op;++i){
while(ql<=qr&&q[ql]+D<i)++ql;
if(ql<=qr)maxs(ans,f1[os[q[ql]]]+f1[os[i]]-q[ql]+i);
while(ql<=qr&&f1[os[q[qr]]]-q[qr]<=f1[os[i]]-i)--qr;
q[++qr]=i;
}
ql=,qr=;
for(int i=op;i;--i){
while(ql<=qr&&q[ql]-D>i)++ql;
if(ql<=qr)maxs(ans,f1[os[q[ql]]]+f1[os[i]]+q[ql]-i);
while(ql<=qr&&f1[os[q[qr]]]+q[qr]<=f1[os[i]]+i)--qr;
q[++qr]=i;
}
}
}
int main(){
fread(buf,,sizeof(buf),stdin);
idp=n=_();m=_();
for(int i=,c,a,b;i<m;++i){
c=_();
a=_();
for(int j=;j<c;++j){
b=_();
ae(e0,a,b,);
a=b;
}
}
tj();
dfs(,);
printf("%d",ans);
return ;
}

2125 多次询问仙人掌上两点间最短路

任意两点a,b间距离分情况考虑,设c=lca(a,b),若c是原有的点,则距离为树上a,b的距离dis(a,b),否则设x,y分别为a,b到c的路径上与c最近的点,则距离为dis(a,x)+dis(b,y)+环上x,y间的距离

倍增或链剖求一下lca再用前缀和特判一下环上情况

#include<cstdio>
#include<algorithm>
char buf[],*ptr=buf-;
int _(){
int x=,c=*++ptr;
while(c<)c=*++ptr;
while(c>)x=x*+c-,c=*++ptr;
return x;
}
const int N=;
int n,m,q;
int es[N],enx[N],ev[N],e0[],e1[],ep=,ss[],sp=,idp,os[],op,d1[],d2[];
int dfn[],low[],tk=;
void ae(int*e,int a,int b,int c){
es[ep]=b;enx[ep]=e[a];ev[ep]=c;e[a]=ep++;
es[ep]=a;enx[ep]=e[b];ev[ep]=c;e[b]=ep++;
}
int min(int a,int b){return a<b?a:b;}
void f0(int w){
dfn[w]=low[w]=++tk;
for(int i=e0[w];i;i=enx[i]){
int u=es[i];
if(!u)continue;
if(!dfn[u]){
ss[++sp]=i;
es[i^]=;
f0(u);
low[w]=min(low[w],low[u]);
if(ss[sp]==i)--sp,ae(e1,w,u,ev[i]);
}else if((low[w]=min(low[w],dfn[u]))==dfn[u]){
++idp;op=;
ae(e1,idp,u,);
op=;
int s1=ev[i],s2=;
while(sp&&dfn[es[ss[sp]]]>dfn[u]){
int e=ss[sp--];
os[op++]=e;
s2+=ev[e];
}
for(int p=;p<op;++p){
int e=os[p];
ae(e1,idp,es[e],min(d1[es[e]]=s1,s2));
d2[es[e]]=s1+s2;
s1+=ev[e],s2-=ev[e];
}
}
}
}
int fa[][],dep[],Dep[];
void f1(int w,int pa){
fa[][w]=pa;
for(int i=e1[w];i;i=enx[i]){
int u=es[i];
if(u==pa)continue;
dep[u]=dep[w]+;
Dep[u]=Dep[w]+ev[i];
f1(u,w);
}
}
int main(){
fread(buf,,sizeof(buf),stdin);
n=_();m=_();q=_();
idp=n;
for(int i=,a,b,c;i<=m;++i){
a=_();b=_();c=_();
ae(e0,a,b,c);
}
f0();
f1(,);
for(int i=;i<;++i)for(int j=;j<=idp;++j)fa[i][j]=fa[i-][fa[i-][j]];
for(int i=,a,b,ans;i<q;++i){
a=_();b=_();
if(dep[a]<dep[b])std::swap(a,b);
ans=Dep[a]+Dep[b];
for(int d=,s=dep[a]-dep[b];d<;++d)if(s>>d&)a=fa[d][a];
if(a==b)ans-=Dep[a]*;
else{
for(int d=;~d;--d)if(fa[d][a]!=fa[d][b])a=fa[d][a],b=fa[d][b];
if(fa[][a]<=n)ans-=Dep[fa[][a]]*;
else{
ans-=Dep[a]+Dep[b];
int s=d1[a]-d1[b];
if(s<)s=-s;
ans+=min(s,d2[a]-s);
}
}
printf("%d\n",ans);
}
return ;
}

4728 带加点、加环操作维护仙人掌最长简单路径

对每条路径,路径上的点不会比两端更晚加入,所以可以离线处理

对新建的树点分治,分别考虑当前分治中心对应的子树(由于根改变,新边权要重新计算),若分治中心为环,则维护环上的前缀max/后缀max(由于环上两点间有两种路径,要分别维护),否则维护每个相邻点方向的最长路径

bzoj 1023: [SHOI2008]cactus仙人掌图 2125: 最短路 4728: 挪威的森林 静态仙人掌上路径长度的维护系列的更多相关文章

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

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

  2. 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图

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

  3. BZOJ 1023: [SHOI2008]cactus仙人掌图 | 在仙人掌上跑DP

    题目: 求仙人掌直径 http://www.lydsy.com/JudgeOnline/problem.php?id=1023 题解: 首先给出仙人掌的定义:满足所有的边至多在一个环上的无向联通图 我 ...

  4. bzoj 1023 [SHOI2008]cactus仙人掌图 ( poj 3567 Cactus Reloaded )——仙人掌直径模板

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1023 http://poj.org/problem?id=3567 因为lyd在讲课,所以有 ...

  5. bzoj 1023: [SHOI2008]cactus仙人掌图

    这道题是我做的第一道仙人掌DP,小小纪念一下…… 仙人掌DP就是环上的点环状DP,树上的点树上DP.就是说,做一遍DFS,DFS的过程中处理出环,环上的点先不DP,先把这些换上的点的后继点都处理出来, ...

  6. BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)

    题目链接 类似求树的直径,可以用(类似)树形DP求每个点其子树(在仙人掌上就是诱导子图)最长链.次长链,用每个点子节点不同子树的 max{最长链}+max{次长链} 更新答案.(不需要存次长链,求解过 ...

  7. bzoj 1023: [SHOI2008]cactus仙人掌图【tarjan+dp+单调队列】

    本来想先求出点双再一个一个处理结果写了很长发现太麻烦 设f[u]为u点向下的最长链 就是再tarjan的过程中,先照常处理,用最长儿子链和次长儿子链更新按ans,然后处理以这个点为根的环,也就是这个点 ...

  8. 1023: [SHOI2008]cactus仙人掌图 - BZOJ

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

  9. 【BZOJ】1023: [SHOI2008]cactus仙人掌图 静态仙人掌(DFS树)

    [题意]给定仙人掌图(每条边至多在一个简单环上),求直径(最长的点对最短路径).n<=50000,m<=10^7. [算法]DFS树处理仙人掌 [题解]参考:仙人掌相关问题的处理方法(未完 ...

随机推荐

  1. LA3029

    题解: 一个类似尺取法的算法 代码: #include<cstdio> #include<algorithm> using namespace std; ; int T,n,m ...

  2. kappa系数在大数据评测中的应用

    ◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/7091315.html 前言 最近打算把翻译质量的人工评测好 ...

  3. IOC与DI简介

    IOC:控制反转(Inverse Of Control) 在没用spring框架之前我们是这样写程序的: private UserDao userDao = new UserDaoImpl(); 也就 ...

  4. LINUX系统中高级网络服务:Bond、Team和网桥

    Bond 一.什么是Bond bond就是将两块网卡虚拟链接成一块网卡的技术.通过bond技术让多块网卡看起来是一个单独的以太网接口设备并具有相同的ip地址. 二.为什么要配置Bond 通过网卡绑定技 ...

  5. vue样式穿透

    在一次这样的需求中,需要实现滑倒底部时自动请求数据,需要动态创建节点然后追加到某元素中,这期间遇到的问题就是在动态创建节点后,类名也已经加上了 ,但是样式就是没有生效,最后发现原因的产生竟然是< ...

  6. Android学习笔记之Android Studio添加新的Activity

    1.创建Android项目工程:AndroidTest 创建过程可参考网上诸多教程. 2.添加新的Activity,步骤如下 a. 在layout文件夹上右键,New-Activity-相应Activ ...

  7. java 输入输出流 关于InputStream 和 OutputSteam 实现文本一行一行读入和 文本一行一行输出

    对  byte 有了新的认知:byte表示一个字节 因此他可以表示成 一个 数字: 一个数字可以映射成一个字符:InputStream 中的 read() 函数  的意思是读入一个整数,读入一个整数的 ...

  8. HihoCoder1164 随机斐波那契(概率DP)

    描述 大家对斐波那契数列想必都很熟悉: a0 = 1, a1 = 1, ai = ai-1 + ai-2,(i > 1). 现在考虑如下生成的斐波那契数列: a0 = 1, ai = aj + ...

  9. BZOJ2131 免费的馅饼【线段树优化DP】

    Input 第一行是用空格隔开的二个正整数,分别给出了舞台的宽度W(1到10^8之间)和馅饼的个数n(1到10^5). 接下来n行,每一行给出了一块馅饼的信息.由三个正整数组成,分别表示了每个馅饼落到 ...

  10. win8.1下安装双系统ubuntu14.04.3

    一.去ubuntu官网下载长期支持版的系统,64位还是32位由物理内存而定,4G以下用32位,4G以上(包括4G)使用64位. 二.若64位的系统,下载下来的文件名应该是ubuntukylin-14. ...