[BZOJ2125]最短路(圆方树DP)
题意:仙人掌图最短路。
算法:圆方树DP,$O(n\log n+Q\log n)$
首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在圆方树上u-v的路径上的所有边权之和,加上每个环(方点)中连出去的两个点的最短距离。
现在问题就是:如何求出环上两个点的最短路径。考虑这样设定边权,首先显然圆圆边的边权就是原图的边权,然后设一个环在搜索树中深度最小的点为这个环的根,则方圆边的边权是环的根到这个点的最短距离,这个可以在Tarjan的时候直接求出。
但是圆方树问题通常需要在LCA处分圆方点讨论。首先如果LCA是圆点,那么直接做即可。如果是方点,就需要决定要不要走环的另一侧,这个同样直接讨论即可。
具体见代码,感觉思路还是比较清晰的。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; const int N=;
int n,m,Q,u,v,w,tot,tim,top,dep[N],len[N],type[N],stk[N];
int dfn[N],low[N],dis[N],lst[N],fa[N][],sm[N][]; struct E{
int cnt,h[N],to[N<<],nxt[N<<],val[N<<];
void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
}G,G1; void work(int x,int k){
tot++; int t; len[tot]=dis[stk[top]]-dis[x]+lst[stk[top]];
do{
t=stk[top--];
int A=dis[t]-dis[x],B=len[tot]-A;
G1.add(tot,t,min(A,B)); type[t]=(A<=B);
}while (t!=k);
G1.add(x,tot,);
} void Tarjan(int x,int pre){
//printf("%d\n",x);
dfn[x]=low[x]=++tim; stk[++top]=x;
for (int i=G.h[x],k; i; i=G.nxt[i]){
if ((k=G.to[i])==pre) continue;
if (!dfn[k]){
dis[k]=dis[x]+G.val[i]; Tarjan(k,x);
//printf("%d %d %d %d\n",x,k,dfn[x],low[k]);
if (low[k]>dfn[x]) top--,G1.add(x,k,G.val[i]);
else if (low[k]==dfn[x]) work(x,k);
low[x]=min(low[x],low[k]);
}else low[x]=min(low[x],dfn[k]),lst[x]=G.val[i];
}
} void dfs(int x,int pre){
for (int i=G1.h[x],k; i; i=G1.nxt[i])
fa[k=G1.to[i]][]=x,dep[k]=dep[x]+,sm[k][]=G1.val[i],dfs(k,x);
} int lca(int u,int v){
if (dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v],res=;
for (int i=; ~i; i--) if (t&(<<i)) res+=sm[u][i],u=fa[u][i];
if (u==v) return res;
for (int i=; ~i; i--) if (fa[u][i]!=fa[v][i])
res+=sm[u][i]+sm[v][i],u=fa[u][i],v=fa[v][i];
if (fa[u][]<=n) return sm[u][]+sm[v][]+res;
int A=sm[u][],B=sm[v][],mn;
if (type[u]==type[v]) mn=min(abs(A-B),len[fa[u][]]-abs(A-B));
else mn=min(A+B,len[fa[u][]]-A-B);
return res+mn;
} int main(){
freopen("bzoj2125.in","r",stdin);
freopen("bzoj2125.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q); tot=n;
rep(i,,m) scanf("%d%d%d",&u,&v,&w),G.add(u,v,w),G.add(v,u,w);
Tarjan(,); dfs(,);
//rep(i,1,tot) printf("%d ",low[i]); puts("");
rep(j,,) rep(i,,tot)
fa[i][j]=fa[fa[i][j-]][j-],sm[i][j]=sm[i][j-]+sm[fa[i][j-]][j-];
rep(i,,Q) scanf("%d%d",&u,&v),printf("%d\n",lca(u,v));
return ;
}
[BZOJ2125]最短路(圆方树DP)的更多相关文章
- BZOJ2125 最短路 圆方树、倍增
传送门 对仙人掌建立圆方树,然后对边定权 对于圆点和圆点之间的边,是原来仙人掌上的桥,边权保持不变 对于圆点和方点之间的边,将圆方树看做以一个圆点为根的有根树之后,一个方点的父亲一定是一个圆点.对于这 ...
- [BZOJ2125]最短路[圆方树]
题意 给定仙人掌,多次询问两点之间的最短路径. \(n\le 10000, Q\le 10000\) 分析 建出圆方树,分路径 lca 是圆点还是方点讨论. 预处理出根圆点到每个圆点的最短距离 \( ...
- BZOJ1023:[SHOI2008]cactus仙人掌图(圆方树,DP,单调队列)
Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus). 所谓简单回路就是指在图上不重复经过任何一个顶点 ...
- 【BZOJ】2125: 最短路 圆方树(静态仙人掌)
[题意]给定带边权仙人掌图,Q次询问两点间最短距离.n,m,Q<=10000 [算法]圆方树处理仙人掌问题 [题解]树上的两点间最短路问题,常用倍增求LCA解决,考虑扩展到仙人掌图. 先对仙人掌 ...
- [BZOJ4316]小C的独立集(圆方树DP)
题意:求仙人掌图直径. 算法:建出仙人掌圆方树,对于圆点直接做普通的树上DP(忽略方点儿子),方点做环上DP并将值直接赋给父亲. 建图时有一个很好的性质,就是一个方点在邻接表里的点的顺序正好就是从环的 ...
- [BZOJ5463][APIO2018]铁人两项(圆方树DP)
题意:给出一张图,求满足存在一条从u到v的长度大于3的简单路径的有序点对(u,v)个数. 做了上一题[HDU5739]Fantasia(点双连通分量+DP),这个题就是一个NOIP题了. 一开始考虑了 ...
- [HDU5739]Fantasia(圆方树DP)
题意:给一张无向点带有权无向图.定义连通图的权值为图中各点权的乘积,图的权值为其包含的各连通图的权和.设z_i为删除i点后图的权值,求$S = (\sum\limits_{i=1}^{n}i\cdot ...
- 洛谷4630APIO2018铁人两项(圆方树+dp)
QWQ神仙题啊(据说是今年第一次出现圆方树的地方) 首先根据题目,我们就是求对于每一个路径\((s,t)\)他的贡献就是两个点之间的点数,但是图上问题我并没有办法很好的解决... 这时候考虑圆方树,我 ...
- 仙人掌&圆方树学习笔记
仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...
随机推荐
- bzoj
准确率爆棚啊,然而
- 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并
我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时 ...
- jQuery知识点:attr与prop的区别
做项目时遇到个莫名的问题,全选的时候仅第一次有效,再次点击全选按钮是无效了,查了查原因,看到篇很不错的文章,问题出在jquery中的attr属性上,这里做下笔记. 原文链接:http://www.cn ...
- [BZOJ1005]Prufer数列+排列组合
一棵树的Prufer数列 每次在剩下的树中找到标号最小的叶子节点(对于无根树而言即是度数为1的节点),删去. 同时将其父节点(即与其相连的唯一点)加入Prufer数列当中. 一个Prufer数列所对应 ...
- #学习方法2打印为空,说明#延迟加载#解决方案:将nameField等设置改在viewDidLoad中设置
#学习方法#error调试#NSLog调试之无法进行数据传输,Edit无法现实之前编辑 的内容 https://www.evernote.com/shard/s227/sh/c ...
- unicode字符串解码显示
# encoding: utf-8 ''' unicode字符串解码显示 ''' import sys reload(sys) sys.setdefaultencoding('utf-8') a = ...
- ubuntu16.04下fcitx无法在QT Creator输入中文解决办法
我的博客新地址:www.liuquanhao.com ------------------------------------------------------ Qt creator无法用fcitx ...
- js面向对象编程(三)非构造函数的继承(转载)
Javascript面向对象编程(三):非构造函数的继承 今天是最后一个部分,介绍不使用构造函数实现"继承". 一.什么是"非构造函数"的继承? 比如,现在有一 ...
- python中进程池的应用
#原创,转载请联系 假设我们写的一个程序需要运行100个子进程的时候,那么写程序时,不可能循环创建销毁100个进程吧?进程的创建与销毁是很耗系统的资源的. 进程池的作用就体现出来了. 进程池可以控制进 ...
- Max-heap && Min-heap && push_heap
最大堆:make_heap(vi.begin(),vi.end()) #include <iostream> #include <vector> #include <al ...