BZOJ2125: 最短路

传送门

圆方树练习。

首先搞出圆方树(建树)。注意在建树的过程中即Tarjan时要同时记录三个信息:1.环的大小。 2.环上每个点到环顶点的距离。 3.最优距离在那一边。

这些都很容易求出来。然后我们把圆点到方点的边权赋为环到顶点的最短距离,方点到圆点的赋为0。

对于每次询问的两个点,询问在圆方树上的LCA,如果LCA是圆点,直接计算即可。下面分析方点的情况。

如果两点的LCA是方点,那么显然在原仙人掌的环上。

这时候对于这个可以选择两条路径,根据题目显然不能暴力走。

对于仙人掌上的两个点,因为我们已经求出最优距离应该走哪一边,而且我们知道了环的大小,所以相对来时没那么优的一条路径也可以计算出来。

所以如果两个点的最优选择是不同方向的,直接用环的大小减去即可。如果是相同方向的,分别计算,取MIN即可。

//BZOJ2125
//by Cydiater
//2017.2.13
#include <iostream>
#include <queue>
#include <map>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <iomanip>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <bitset>
#include <set>
#include <vector>
#include <complex>
using namespace std;
#define ll long long
#define up(i,j,n)	for(int i=j;i<=n;i++)
#define down(i,j,n)	for(int i=j;i>=n;i--)
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b)	a=min(a,b)
#define Auto(i,node)	for(int i=LINK[node];i;i=e[i].next)
const int MAXN=1e5+5;
const int oo=0x3f3f3f3f;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
int N,M,Q,NN,Girth[MAXN];
vector<int>E[MAXN],W[MAXN];
bool cho[MAXN];
struct Info{
	int sx,sy,lca;
};
struct Graph{
	int LINK[MAXN],len,dfn[MAXN],low[MAXN],stack[MAXN],top,dfs_clock,dep[MAXN],fa[MAXN][25],dis[MAXN][25];
	struct edge{
		int y,next,v;
	}e[MAXN];
	inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;}
	inline void Insert(int x,int y,int v){insert(x,y,v);insert(y,x,v);}
	int Col(int id){
		int dist=0,siz=E[id].size();
		up(i,0,siz-1){
			int x=E[id][i],y=E[id][(i+1)%siz];
			Auto(j,x)if(e[j].y==y){
				dist+=e[j].v;
				W[id].push_back(e[j].v);
			}
		}
		return dist;
	}
	void Tarjan(int node){
		dfn[node]=low[node]=++dfs_clock;
		stack[++top]=node;
		Auto(i,node)if(!dfn[e[i].y]){
			Tarjan(e[i].y);
			cmin(low[node],low[e[i].y]);
			if(low[e[i].y]>=dfn[node]){
				NN++;int tmp;
				do{
					tmp=stack[top--];
					E[NN].push_back(tmp);
				}while(tmp!=e[i].y);
				E[NN].push_back(node);
				Girth[NN]=Col(NN);
			}
		}else cmin(low[node],dfn[e[i].y]);
	}
	void DFS(int node,int father,int deep){
		fa[node][0]=father;dep[node]=deep;
		Auto(i,node)if(e[i].y!=father)
			DFS(e[i].y,node,deep+1);
		if(node>N){
			dis[node][0]=0;
			int siz=E[node].size(),dist=0;
			down(j,siz-2,0){
				dist+=W[node][j];
				dis[E[node][j]][0]=min(dist,Girth[node]-dist);
				if(dis[E[node][j]][0]==dist)	cho[E[node][j]]=0;
				else 				cho[E[node][j]]=1;
			}
		}
	}
	void Get_Ancestor(){
		up(i,1,20)up(node,1,N)if(fa[node][i-1]){
			fa[node][i]=fa[fa[node][i-1]][i-1];
			dis[node][i]=dis[node][i-1]+dis[fa[node][i-1]][i-1];
		}
	}
	Info LCA(int x,int y){
		if(x==y)	return (Info){0,0,x};
		if(dep[x]<dep[y])swap(x,y);
		down(i,20,0)if(dep[x]-(1<<i)>=dep[y])x=fa[x][i];
		if(x==y)	return (Info){0,0,x};
		down(i,20,0)if(fa[x][i]!=0&&fa[x][i]!=fa[y][i]){
			x=fa[x][i];
			y=fa[y][i];
		}
		return (Info){x,y,fa[x][0]};
	}
	int Get(int node,int aim){
		int ans=0;
		down(i,20,0)if(dep[node]-(1<<i)>=dep[aim]){
			ans+=dis[node][i];
			node=fa[node][i];
		}
		return ans;
	}
}G1,G2;
namespace solution{
	void Prepare(){
		N=read();M=read();Q=read();
		while(M--){
			int x=read(),y=read(),v=read();
			G1.Insert(x,y,v);
		}
		NN=N;
		G1.Tarjan(1);
		up(i,N+1,NN){
			int siz=E[i].size();
			up(j,0,siz-1)G2.Insert(i,E[i][j],0);
		}
		G2.DFS(1,0,0);
		G2.Get_Ancestor();
		//up(i,1,N)cout<<G2.dis[i][0]<<endl;
	}
	void Solve(){
		while(Q--){
			int x=read(),y=read(),ans=0;
			Info info=G2.LCA(x,y);
			int lca=info.lca,sx=info.sx,sy=info.sy;
			if(lca>N){
				int tmp;
				if(cho[sx]^cho[sy])	tmp=G2.dis[sx][0]+G2.dis[sy][0];
				else			tmp=min(Girth[lca]-G2.dis[sx][0]+G2.dis[sy][0],Girth[lca]-G2.dis[sy][0]+G2.dis[sx][0]);
				ans=G2.Get(x,sx)+G2.Get(y,sy)+min(G2.dis[sx][0]+G2.dis[sy][0],Girth[lca]-tmp);
			}
			else		ans=G2.Get(x,lca)+G2.Get(y,lca);
			printf("%d\n",ans);
		}
	}
}
int main(){
	using namespace solution;
	Prepare();
	Solve();
	return 0;
}
时间: 2024-10-20 06:59:37

BZOJ2125: 最短路的相关文章

bzoj2125 最短路——仙人掌两点间距离

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125 仙人掌!模仿 lyd 的代码写的,也算是努力理解了: 主要分成 lca 在环上和不在环上,先缩环(环上的点直接连向最高点),那么不在环上的 lca 就跟在树上一样求法: 在环上的话就先求出环外部分,再计算环内距离: 所以一遍 spfa 求从根出发的最短路,再一遍 dfs 求 dfs 序的 dis ,用来处理环上距离,然后 bfs 计算深度用来倍增求 lca,然后分类求答案即可: 注意

【题解】Bzoj2125最短路

处理仙人掌 ---> 首先建立出圆方树.则如果询问的两点 \(lca\) 为圆点,直接计算即可, 若 \(lca\) 为方点,则需要额外判断是走环的哪一侧(此时与两个点在环上的相对位置有关.) #include <bits/stdc++.h> using namespace std; #define maxn 200000 #define int long long #define CNST 20 int n, m, Q, gra[maxn][CNST]; int N, dfn[maxn

bzoj3047:Freda的传呼机&amp;&amp;bzoj2125: 最短路

完结撒花!!!!!!!!!!! 最后一题填坑1A仙人掌WWWWWWW我真流弊 首先把环拆开,环中每一个点连向环的根,然后搞LCA,答案就是套路的d[x]+d[y]-d[lca]*2 然后就可以发现,其实只有当fx和fy在同一个环里面,才有可能通过不同的路线导致答案更小,特判之即可. #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algor

hdu3461Marriage Match IV 最短路+最大流

//给一个图.给定起点和终点,仅仅能走图上的最短路 //问最多有多少种走的方法.每条路仅仅能走一次 //仅仅要将在最短路上的全部边的权值改为1.求一个最大流即可 #include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<vector> using namespace std ; const int inf = 0x3f3f3f3f ; const

UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的T-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据. 每组数据第一行是两个整数NN ,MM (N≤100N≤100 ,M≤10000M≤1000

ACM: HDU 2544 最短路-Dijkstra算法

HDU 2544最短路 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据.每组数据第一行是两个整数N.M(N<=100,M<

ACM/ICPC 之 昂贵的聘礼-最短路解法(POJ1062)

//转移为最短路问题,枚举必经每一个不小于酋长等级的人的最短路 //Time:16Ms Memory:208K #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define INF 0x3f3f3f3f #define MAX 105 int lim, n; int p[M

图论(A*算法,K短路) :POJ 2449 Remmarguts&#39; Date

Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 25216   Accepted: 6882 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, h

hdu4725 拆点+最短路

题意:有 n 个点,每个点有它所在的层数,最多有 n 层,相邻两层之间的点可以互相到达,消耗 c (但同一层并不能直接到达),然后还有一些额外的路径,可以在两点间互相到达,并且消耗一定费用.问 1 点到 n 点的最小花费 将每一层拆成两个点,分别为进入层和出发层,然后相邻层的出发层可以指向进入层,花费 c,每个点可以到达其出发层,而进入层可以到达该点,花费 0 ,最后建立其余双向边,最短路 1 #include<stdio.h> 2 #include<string.h> 3 #in