[BZOJ2125]最短路[圆方树]
题意
给定仙人掌,多次询问两点之间的最短路径。
\(n\le 10000, Q\le 10000\)
分析
- 建出圆方树,分路径 lca 是圆点还是方点讨论。
 - 预处理出根圆点到每个圆点的最短距离 \(dis\) 。
 - 如果 lca 是圆点,那么最短距离就是 \(dis_a+dis_b-2*dis_{lca}\)。
 - 否则找到 lca 到 a, b 路径上的第一个圆点 x, y,最短距离即 \(dis_a-dis_x+dis_b-dis_y+dist(x, y)\) 。其中 \(dist(x, y)\) 表示在同一个环中的两个节点 \(x, y\) 之间的最短距离。
 - 复杂度 \(O(nlogn+Qlogn)\) 。
 
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi() {
    int x = 0,f = 1;
    char ch = getchar();
    while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
    while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
    return x * f;
}
template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
const int N = 2e4 + 7;
int n, m, edc, dfn, tp, ndc, ans, Q;
int low[N], pre[N], stk[N], f[N][2], head[N];
int up[N][18], s[N], dis[N], tot[N], dep[N];
vector<int>G[N];
map<pair<int, int>, int> dist;
struct edge {
	int lst, to;
	edge(){}edge(int lst, int to):lst(lst), to(to){}
}e[N << 1];
void Add(int a, int b) {
	e[++edc] = edge(head[a], b), head[a] = edc;
	e[++edc] = edge(head[b], a), head[b] = edc;
}
void tarjan(int u, int fa) {
	low[u] = pre[u] = ++dfn;
	stk[++tp] = u;
	go(u)if(v ^ fa) {
		if(!low[v]) {
			tarjan(v, u);
			Min(pre[u], pre[v]);
			if(pre[v] >= low[u]) {
				G[u].pb(++ndc);
				for(int x = -1; x ^ v; )
				G[ndc].pb(x = stk[tp--]);
			}
		}else Min(pre[u], low[v]);
	}
}
#define mp make_pair
void dfs(int u, int fa) {
	up[u][0] = fa;
	for(int i = 1; i <= 17; ++i) up[u][i] = up[up[u][i - 1]][i - 1];
	if(u > n) {
		tot[u] += dist[mp(fa, G[u][0])];
		s[G[u][0]] = dist[mp(fa, G[u][0])];
		for(int i = 1; i < G[u].size(); ++i) {
			s[G[u][i]] = s[G[u][i - 1]] + dist[mp(G[u][i - 1], G[u][i])];
			tot[u] += dist[mp(G[u][i - 1], G[u][i])];
		}
		tot[u] += dist[mp(fa, G[u][G[u].size() - 1])];
	}
	for(int i = 0; i < G[u].size(); ++i) {
		int v = G[u][i];
		dep[v] = dep[u] + 1;
		if(u > n) dis[v] = dis[fa] + min(s[v], tot[u] - s[v]);
		dfs(v, u);
	}
}
int get(int a, int b) {
	if(a == b) return 0;
	if(dep[a] > dep[b]) swap(a, b);
	int x = a, y = b;
	for(int i = 17; ~i; --i) if(dep[up[b][i]] >= dep[a]) b = up[b][i];
	if(a == b) {
		b = y;
		for(int i = 17; ~i; --i) if(dep[up[b][i]] > dep[a]) b = up[b][i];
		if(a <= n) return dis[y] - dis[a];
		return dis[y] - dis[b];
	}
	for(int i = 17; ~i; --i) if(up[a][i] != up[b][i]){
		a = up[a][i];
		b = up[b][i];
	}
	int lca = up[a][0];
	if(lca <= n) {
		return dis[x] + dis[y] - 2 * dis[lca];
	}else {
		return dis[x] - dis[a] + dis[y] - dis[b] + min(abs(s[b] - s[a]), tot[lca] - abs(s[b] - s[a]));
	}
}
int main() {
	n = gi(), m = gi();Q = gi();ndc = n;
	rep(i, 1, m) {
		int a = gi(), b = gi(), c = gi();
		Add(a, b);
		dist[make_pair(a, b)] = dist[make_pair(b, a)] = c;
	}
	tarjan(1, 0);
	dep[1] = 1, dfs(1, 0);
	while(Q--) {
		int a = gi(), b = gi();
		printf("%d\n", get(a, b));
	}
	return 0;
}
												
											[BZOJ2125]最短路[圆方树]的更多相关文章
- [BZOJ2125]最短路(圆方树DP)
		
题意:仙人掌图最短路. 算法:圆方树DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在 ...
 - BZOJ2125 最短路 圆方树、倍增
		
传送门 对仙人掌建立圆方树,然后对边定权 对于圆点和圆点之间的边,是原来仙人掌上的桥,边权保持不变 对于圆点和方点之间的边,将圆方树看做以一个圆点为根的有根树之后,一个方点的父亲一定是一个圆点.对于这 ...
 - 【BZOJ】2125: 最短路 圆方树(静态仙人掌)
		
[题意]给定带边权仙人掌图,Q次询问两点间最短距离.n,m,Q<=10000 [算法]圆方树处理仙人掌问题 [题解]树上的两点间最短路问题,常用倍增求LCA解决,考虑扩展到仙人掌图. 先对仙人掌 ...
 - 仙人掌&圆方树学习笔记
		
仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...
 - 【BZOJ2125】最短路(仙人掌,圆方树)
		
[BZOJ2125]最短路(仙人掌,圆方树) 题面 BZOJ 求仙人掌上两点间的最短路 题解 终于要构建圆方树啦 首先构建出圆方树,因为是仙人掌,和一般图可以稍微的不一样 直接\(tarjan\)缩点 ...
 - 2018.07.25 bzoj2125: 最短路(圆方树+倍增)
		
传送门 人生的第一道仙人掌. 这道题求是仙人掌上的最短路. 先建出圆方树,然后用倍增跑最短路,当lca" role="presentation" style=" ...
 - bzoj 2125 最短路 点双 圆方树
		
LINK:最短路 一张仙人掌图 求图中两点最短路. \(n<=10000,Q<=10000,w>=1\) 考虑边数是多少 m>=n-1 对于一张仙人掌图 考虑先构建出来dfs树 ...
 - BZOJ.2125.最短路(仙人掌 圆方树)
		
题目链接 圆方树.做题思路不写了.. 就是当LCA是方点时跳进那个环可以分类讨论一下用树剖而不必须用倍增: 如果v是u的(唯一的那个)重儿子,那么u的DFS序上+1的点即是要找的:否则v会引出一条新的 ...
 - 图论杂项细节梳理&模板(虚树,圆方树,仙人掌,欧拉路径,还有。。。)
		
orzYCB 虚树 %自为风月马前卒巨佬% 用于优化一类树形DP问题. 当状态转移只和树中的某些关键点有关的时候,我们把这些点和它们两两之间的LCA弄出来,以点的祖孙关系连成一棵新的树,这就是虚树. ...
 
随机推荐
- Asp.Net Core 使用Quartz基于界面画接口管理做定时任务
			
今天抽出一点点时间来造一个小轮子,是关于定时任务这块的. 这篇文章主要从一下几点介绍: 创建数据库管理表 创建web项目 引入quarzt nuget 包 写具体配置操作,实现定时任务处理 第一步:创 ...
 - 07-OpenLDAP密码审计
			
OpenLDAP密码审计 阅读视图 密码审计的作用 操作实践 1. 密码审计的作用 开启密码审计的功能主要用于记录OpenLDAP用户修改密码,以及密码审计. 2. 操作实践 开启密码审计模块并配置密 ...
 - python UDP套接字通信
			
UDPserver.py import socket #导入套接字模块 s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # - socket.A ...
 - chrony时间服务器
			
chrony有着比ntp服务器更好的优势来同步服务,在集群架构中,采用此种服务来同步时间也是最好的方式. 在集群环境中,一般都是一个服务器,然后上百个客户端来同步服务端的时间,接下来我们看看如何配置. ...
 - logstash之input、codec学习
			
Logstash最强大的功能在于丰富的过滤器插件.此过滤器提供的并不单单是过滤的功能,还可以对进入过滤器的原始数据进行复杂的逻辑处理.甚至添加独特的事件到后续流程中. 1.logstash基本语法组成 ...
 - Linux 小知识翻译 - 「i386」是什么?
			
i386是指 *CPU* 的种类,也可以指 *CPU* 的架构(architecture). 现在的 CPU 一般都用 「Core 2 Duo」或者「Athlon」,「Xeon」,「Opteron」之 ...
 - January 05th, 2018 Week 01st Friday
			
You can't make decisions based on fear and the possibility of what might happen. 不要因为恐惧未知的可能而妄下决定. P ...
 - 第一条:了解Objective-C语言的起源
			
第一条:了解Objective-C语言的起源 Objective-C使用的消息结构而非函数调用. Objective-C的重要工作都由"运行组件(runtime component)&quo ...
 - pThreads线程(一)  基本API
			
1.创建线程 int pthread_create(pthread_t *restrict_ptid, const pthread_attr_t *restrict_att ...
 - 让zepto支持slideup(),slidedown()
			
zepto不支持slideup()和slidedown():使用以下方法可以支持该功能 <div class="slide"> <p> zepto不支持sl ...