2018牛客 国庆Day6 J-最短路

链接:https://www.nowcoder.com/acm/contest/206/J

题目描述

给一个连通图,每次询问两点间最短路。每条边的长度都是1。

输入描述:

第一行两个整数n和m,表示图的点数和边数(1 ≤ n ≤ 100000, 1 ≤ m  ≤ n+100)。
接下来m行每行两个整数a和b,表示一条边(1 ≤  a, b ≤  n)。保证没有自环和重边。保证图连通。
接下来一个整数q表示询问的个数(1≤ q≤ 100000)。
接下来q行每行两个整数a和b表示询问a和b之间的最短路。

输出描述:

每个询问输出一行表示答案。

输入

4 5
1 2
2 3
1 4
4 3
2 4
4
1 4
1 2
2 4
1 3

输出

1
1
1
2

思路

题目给了1e5个点,但是却问你多源最短路,直接跑floyed(n^3)是肯定不行的,但是边数最多只有1e5+100条边,我们就可以先用并查集建一棵树,多下来的100条边先存在一边,然后跑lca(st表/tarjan离线/树链剖分)跑完之后再把前面存起来的100条边给加回这个图里,并且从这100条边的每个点开始跑单源最短路(dij/spfa),当然这里因为每条路的权值都为1,跑bfs其实也是可以的,最后的答案就是树上dist和所有单源最短路中的那个最小值。

垃圾牛客!!!各种卡时间!!!

#include <iostream>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#include <algorithm>
#include <queue>
#include <set>
#include <cmath>
#include <sstream>
#include <stack>
#include <fstream>
#include <ctime>
#pragma warning(disable:4996);
#define mem(sx,sy) memset(sx,sy,sizeof(sx))
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const double PI = acos(-1.0);
const ll llINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
using namespace std;
#define pa pair<int, int>
//const int mod = 1e9 + 7;
const int maxn = 200006;
inline void scan_d(int &ret) {
	char c;
	ret = 0;
	while ((c = getchar()) < '0' || c > '9');
	while (c >= '0' && c <= '9')
	{
		ret = ret * 10 + (c - '0'), c = getchar();
	}
}

struct node {
	int u, v, w, next, lca;
};

struct LCA {
	node edges[maxn << 1];
	int head[maxn << 1], cnt1;
	int id[maxn << 1], in[maxn << 1], Dep[maxn << 1], Dist[maxn << 1], cnt2;
	int RMQ[maxn << 1][20];
	void addedge(int u, int v, int w) {
		edges[cnt1].v = v;
		edges[cnt1].w = w;
		edges[cnt1].next = head[u];
		head[u] = cnt1++;
	}

	void init() {
		mem(head, -1);
		cnt1 = 0;
		cnt2 = 0;
	}

	void DFS(int u, int f, int d, int dis) {
		in[++cnt2] = u;
		Dep[cnt2] = d;
		id[u] = cnt2;
		Dist[u] = dis;
		for (int i = head[u]; i != -1; i = edges[i].next) {
			int v = edges[i].v;
			if (v == f) continue;
			DFS(v, u, d + 1, dis + 1);
			in[++cnt2] = u;
			Dep[cnt2] = d;
		}
	}

	void initRMQ() {
		for (int i = 1; i <= cnt2; i++)
			RMQ[i][0] = i;
		for (int j = 1; (1 << j) <= cnt2; j++) {
			for (int i = 1; i + (1 << j) - 1 <= cnt2; i++) {
				int x = RMQ[i][j - 1];
				int y = RMQ[i + (1 << (j - 1))][j - 1];
				RMQ[i][j] = Dep[x] < Dep[y] ? x : y;
			}
		}
	}

	int getLCA(int a, int b) {
		int k, x, y;
		a = id[a]; b = id[b];
		if (a > b)swap(a, b);
		k = log(1.0 + b - a) / log(2.0);
		x = RMQ[a][k];
		y = RMQ[b - (1 << k) + 1][k];
		return Dep[x] < Dep[y] ? in[x] : in[y];
	}

	int getdist(int x, int y) {
		return Dist[x] + Dist[y] - 2 * Dist[getLCA(x, y)];
	}
}L;

int fa[100006];
int Find(int x) {
	if (x == fa[x]) {
		return x;
	}
	return fa[x] = Find(fa[x]);
}
void Union(int x, int y) {
	x = Find(x);
	y = Find(y);
	if (x != y) {
		fa[x] = y;
	}
}

int dist[210][100006];
int vis[100006];
int inq[100006];
vector<pa>G;
void spfa(int cnt, int u, int n) {
	for (int i = 1; i <= n; i++) {
		dist[cnt][i] = INF;
		inq[i] = false;
	}
	dist[cnt][u] = 0;
	inq[u] = true;
	queue<int> Q;
	Q.push(u);
	while (!Q.empty()) {
		u = Q.front(); Q.pop();
		inq[u] = false;
		for (int i = L.head[u]; i != -1; i = L.edges[i].next) {
			int v = L.edges[i].v;
			if (dist[cnt][v] > dist[cnt][u] + 1) {
				dist[cnt][v] = dist[cnt][u] + 1;
				if (!inq[v]) {
					inq[v] = true;
					Q.push(v);
				}
			}
		}
	}
}
int main() {
	int n, m;
	//scanf("%d%d", &n, &m);
	scan_d(n), scan_d(m);
	for (int i = 0; i <= n; i++) {
		fa[i] = i;
	}
	L.init();
	for (int i = 0, u, v; i < m; i++) {
		//scanf("%d%d", &u, &v);
		scan_d(u), scan_d(v);
		if (Find(u) != Find(v)) {
			Union(u, v);
			L.addedge(u, v, 1);
			L.addedge(v, u, 1);
		}
		else {
			G.push_back(pa(u, v));
		}
	}
	L.DFS(1, 0, 0, 0);
	L.initRMQ();

	int cnt = 0;
	for (auto it : G) {
		int u = it.first, v = it.second;
		L.addedge(u, v, 1);
		L.addedge(v, u, 1);
	}

	mem(vis, 0);
	for (auto it : G) {
		if (!vis[it.first]) {
			vis[it.first] = 1;
			spfa(cnt++, it.first, n);
		}
	}

	int Q;
	//scanf("%d", &Q);
	scan_d(Q);
	while (Q--) {
		int u, v;
		//scanf("%d%d", &u, &v);
		scan_d(u), scan_d(v);
		int ans = L.getdist(u, v);
		for (int i = 0; i < cnt; i++) {
			ans = min(ans, dist[i][u] + dist[i][v]);
		}
		printf("%d\n", ans);
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值