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;
}