洛谷P4320 道路相遇(LCA+圆方树)
题目链接:https://www.luogu.com.cn/problem/P4320
道路相遇
题目描述
在 H 国的小 w 决定到从城市 $u$ 到城市 $v$ 旅行,但是此时小 c 由于各种原因不在城市 $u$,但是小 c 决定到在中途与小 w 相遇
由于 H 国道路的原因,小 w 从城市 $u$ 到城市 $v$ 的路线不是固定的,为了合理分配时间,小 c 想知道从城市 $u$ 到城市 $v$ 有多少个城市小 w 一定会经过,特别地,$u, v$ 也必须被算进去,也就是说无论如何答案不会小于 2
由于各种特殊的原因,小 c 并不知道小 w 的起点和终点,但是小 c 知道小 w 的起点和终点只有 $q$ 种可能,所以对于这 $q$ 种可能,小 c 都想知道小 w 一定会经过的城市数
H 国所有的边都是无向边,两个城市之间最多只有一条道路直接相连,没有一条道路连接相同的一个城市
任何时候,H 国不存在城市 $u$ 和城市 $v$ 满足从 $u$ 无法到达 $v$
输入格式
第一行两个正整数 $n,m$,表示 H 国的城市数,以及道路数。
下面 $m$ 行,每行两个不同的正整数 $u, v$,表示城市 $u$ 到城市 $v$ 之间有一条边。
然后一行一个正整数 $q$。
接下来 $q$ 行,每行两个正整数 $u, v$ 表示小 w 旅行的一种可能的路线
输出格式
输出共 $q$ 行,每行一个正整数
样例 #1
样例输入 #1
5 6
1 2
1 3
2 3
3 4
4 5
3 5
1
1 5
样例输出 #1
3
提示
从城市 $1$ 到城市 $5$ 总共有 $4$ 种可能 :
$1 \to 2 \to 3 \to 4 \to 5$
$1 \to 2 \to 3 \to 5$
$1 \to 3 \to 4 \to 5$
$1 \to 3 \to 5$
可以发现小 w 总会经过城市 $1,3,5$,所以答案为 $3$
你可以认为小 w 不会经过相同的城市两次,当然,如果你认为可以经过相同的城市两次也不会影响答案
subtask1 : 15分,$m = 5, q = 50$
subtask2 : 15分,$n = 100, q = 5000$
subtask3 : 20分,$n = 3000, q = 5\times 10^5$
subtask4 : 20分,$n = 499999, q = 5 \times 10^5, m = n-1$
subtask5 : 30分,$n = q = 5 \times 10^5$
对于所有数据 : $1\leq n\leq 5 \times 10^5, 1\leq q\leq 5\times 10^5, 1\leq m\leq \min(\frac{n(n-1)}{2}, 10^6)$
代码:
1 #include<iostream>
2 #include<cstdio>
3 #include<vector>
4 #include<map>
5 #include<queue>
6 #include<set>
7 #include<algorithm>
8 #include<stack>
9 #include<cmath>
10 #include<cstring>
11 #include<string>
12 using namespace std;
13 #define gc getchar()
14 #define rd(x) read(x)
15 #define el '\n'
16 #define rep(i, a, n) for(int i = (a); i <= n; ++i)
17 #define per(i, a, n) for(int i = (a); i >= n; --i)
18 using ll = long long;
19 using db = double;
20 using ldb = long double;
21 const int N = 500000 + 10;
22 const int mod = 1e9 + 7;
23 const int inf = 0x3f3f3f3f;
24
25 template <typename _T>
26 inline void read(_T& f) {
27 f = 0; _T fu = 1; char c = gc;
28 while (c < '0' || c > '9') { if (c == '-') { fu = -1; } c = gc; }
29 while (c >= '0' && c <= '9') { f = (f << 3) + (f << 1) + (c & 15); c = gc; }
30 f *= fu;
31 }
32
33 template <typename T>
34 void print(T x) {
35 if (x < 0) putchar('-'), x = -x;
36 if (x < 10) putchar(x + 48);
37 else print(x / 10), putchar(x % 10 + 48);
38 }
39
40 template <typename T>
41 void print(T x, char t) {
42 print(x); putchar(t);
43 }
44
45 int n, m;
46 vector<int>G[N << 2];
47
48 struct node {
49 int to, w, next;
50 }e[N << 2];
51 int head[N << 2], tot;
52
53 void add(int u, int v) {
54 e[tot].to = v;
55 //e[tot].w = w;
56 e[tot].next = head[u];
57 head[u] = tot++;
58 }
59
60 int dfn[N << 2], low[N << 2], dfc;
61 int stk[N << 2], tp, bcc;
62
63 void tarjan(int u) {
64
65 dfn[u] = low[u] = ++dfc;
66 stk[++tp] = u;
67 for (int i = 0; i < (int)G[u].size(); i++) {
68 int v = G[u][i];
69 if (!dfn[v]) {
70 tarjan(v);
71 low[u] = min(low[u], low[v]);
72 if (low[v] == dfn[u]) {
73 bcc++;
74 for (int x = 0; x != v; tp--) {
75 x = stk[tp];
76 add(x, bcc), add(bcc, x);
77 }
78 add(u, bcc), add(bcc, u);
79 }
80 }
81 else low[u] = min(low[u], dfn[v]);
82 }
83
84 }
85
86 int fa[N << 2][31], dep[N << 2];
87
88 void dfs(int x, int pre) {
89
90 fa[x][0] = pre;
91 dep[x] = dep[pre] + 1;
92 for (int i = 1; i <= 30; i++) {
93 fa[x][i] = fa[fa[x][i - 1]][i - 1];
94 }
95 for (int i = head[x]; i + 1; i = e[i].next) {
96 int to = e[i].to;
97 if (to != pre) dfs(to, x);
98 }
99
100 }
101
102 int lca(int x, int y) {
103
104 if (dep[x] < dep[y]) swap(x, y);
105 for (int i = 30; i >= 0; i--) {
106 if ((1 << i) <= dep[x] - dep[y]) x = fa[x][i];
107 }
108 if (x == y) return x;
109 for (int i = 30; i >= 0; i--) {
110 if (fa[x][i] != fa[y][i]) {
111 x = fa[x][i];
112 y = fa[y][i];
113 }
114 }
115
116 return fa[x][0];
117 }
118
119 int main() {
120
121 ios::sync_with_stdio(false);
122 cin.tie(0), cout.tie(0);
123 memset(head, -1, sizeof(head));
124 cin >> n >> m;
125 bcc = n;
126 for (int i = 1; i <= m; i++) {
127 int u, v;
128 cin >> u >> v;
129 G[u].push_back(v);
130 G[v].push_back(u);
131 }
132 //cout << el;
133 tarjan(1);
134 /*for(int i = n + 1; i <= bcc; i++) {
135 for(int j = head[i]; j + 1; j = e[j].next) {
136 cout << i << ' ' << e[j].to << el;
137 }
138 //cout << el;
139 }
140 cout << el;*/
141 dfs(1, 1);
142 int q;
143 cin >> q;
144 for (; q; --q) {
145 int u, v;
146 cin >> u >> v;
147 int p = lca(u, v);
148 //cout << p << el;
149 int ans;
150 if (p > n) {
151 ans = (dep[u] - dep[p] + 1) / 2 + (dep[v] - dep[p] + 1) / 2;
152 }
153 else {
154 ans = (dep[u] - dep[p]) / 2 + (dep[v] - dep[p]) / 2 + 1;
155 }
156 cout << ans << el;
157 }
158
159 return 0;
160 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】