P4768 [NOI2018] 归程(kruskal 重构树)
生活随笔
收集整理的這篇文章主要介紹了
P4768 [NOI2018] 归程(kruskal 重构树)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
P4768 [NOI2018] 歸程
給定一個nnn個點,mmm條邊的無向聯通圖,邊的描述為[u,v,l,a][u, v, l, a][u,v,l,a],表示uuu,vvv連有一條長度為lll,海拔為aaa的邊,
有QQQ個詢問,每次給出一個出發點uuu和一個海拔限制高度ppp,并且在出發點有一輛車,這輛車可以通過海拔大于ppp的邊,
問,從u?>1u->1u?>1的最短步行長度是什么多少。
設從uuu坐車出發可到的點集為SSS,我們的任務就是找到一個點v,v∈Sv, v \in Sv,v∈S,dis(v,1)dis(v, 1)dis(v,1)是dis(x,1),x∈Sdis(x, 1),x \in Sdis(x,1),x∈S中最的小。
① 預處理出每個點到點111的最短路徑出來,
② 我們按照海拔高度降序建立一顆kruskalkruskalkruskal重構樹,
③ 從uuu號點往上跳,找到可坐車到達的深度最小的節點rtrtrt,顯然從uuu可坐車到達的點集就是rtrtrt所在的這顆子樹,
④ 由于我們查找的是最小值,所以只需在dfsdfsdfs的過程中,不斷向上更新整顆子樹的最小值即可。
⑤ 直接輸出我們找到的rtrtrt所代表的答案。
#include <bits/stdc++.h>using namespace std;const int N = 1e6 + 10;int head[N], to[N], nex[N], cnt = 1;int head1[N], to1[N], nex1[N], value1[N], cnt1 = 1;int vis[N], dis[N], ff[N], value[N], fa[N][21], ans[N], nn, n, m, Q, K, S;struct Edge {int u, v, w;bool operator < (const Edge &t) const {return w > t.w;} }edge[N];struct Node {int u, w;bool operator < (const Node &t) const {return w > t.w;} };void add1(int x, int y, int w) {to1[cnt1] = y;nex1[cnt1] = head1[x];value1[cnt1] = w;head1[x] = cnt1++; }void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++; }priority_queue<Node> q;void Dijkstra() {while (q.size()) {q.pop();}q.push({1, 0});memset(vis, 0, sizeof vis), memset(dis, 0x3f, sizeof dis);dis[1] = 0;while (q.size()) {int rt = q.top().u;q.pop();if (vis[rt]) {continue;}vis[rt] = 1;for (int i = head1[rt]; i; i = nex1[i]) {if (dis[to1[i]] > dis[rt] + value1[i]) {dis[to1[i]] = dis[rt] + value1[i];q.push({to1[i], dis[to1[i]]});}}} }int find(int rt) {return ff[rt] == rt ? rt : ff[rt] = find(ff[rt]); }void dfs(int rt, int f) {fa[rt][0] = f, ans[rt] = rt <= n ? dis[rt] : 0x3f3f3f3f;for (int i = 1; i <= 20; i++) {fa[rt][i] = fa[fa[rt][i - 1]][i - 1];}for (int i = head[rt]; i; i = nex[i]) {if (to[i] == f) {continue;}dfs(to[i], rt);ans[rt] = min(ans[rt], ans[to[i]]);} }void kruskal() {for (int i = 1; i < N; i++) {ff[i] = i, head[i] = 0;}cnt = 1;sort(edge + 1, edge + 1 + m);for (int i = 1, cur = 1; i <= m && cur < n; i++) {int u = find(edge[i].u), v = find(edge[i].v);if (u != v) {cur++, nn++;ff[u] = nn, ff[v] = nn;value[nn] = edge[i].w;add(nn, u), add(nn, v);if (u <= n) {value[u] = edge[i].w;}if (v <= n) {value[v] = edge[i].w;}}}dfs(nn, 0); }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int T;scanf("%d", &T);while (T--) {scanf("%d %d", &n, &m);nn = n;memset(head1, 0, sizeof head1), cnt1 = 1;for (int i = 1, u, v, l, a; i <= m; i++) {scanf("%d %d %d %d", &u, &v, &l, &a);add1(u, v, l), add1(v, u, l);edge[i] = {u, v, a};}Dijkstra();kruskal();scanf("%d %d %d", &Q, &K, &S);for (int i = 1, v, p, last_ans = 0; i <= Q; i++) {scanf("%d %d", &v, &p);v = (v + 1ll * K * last_ans - 1) % n + 1, p = (p + 1ll * K * last_ans) % (S + 1);for (int j = 20; j >= 0; j--) {if (fa[v][j] && value[fa[v][j]] > p) {v = fa[v][j];}}last_ans = ans[v];printf("%d\n", last_ans);}}return 0; }總結
以上是生活随笔為你收集整理的P4768 [NOI2018] 归程(kruskal 重构树)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python数据分析工具Pandas——
- 下一篇: 轻松理解箱形图