链接: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);
}
}