题目链接:​​传送门​

kruskal重构树
具体什么原理可以来​这里​瞅一下
根据海拔高度建出kruskal重构树
海拔高的在前面
这样重构树的根节点的海拔最小
查询的时候只要某个子树的根节点能到
那子树也一定能到
且走到子树的点都没有花费
lca的点权的意义是路上最短边的最大值
题目中我们可以通过汽车走一段没有花费的路程
就是在这里处理的
还需要求一个最小的花费
这个花费是这个子树中所有节点的最小花费
是到1节点的
每个节点到1节点的最短路可以预处理
然后再处理出每个子树的最小花费
就做完啦
“关于SPFA”
“他死了”
就是出自这个题
所以好好堆优Dij叭
所以流程:
Dij最短路求每个点到1号点的最短路->
建出以海拔为权值从大到小排序的Kruskal重构树->
处理出重构树中每个子树到1号点的最短距离->
找到点权大于水位线的那个点输出上一步处理出的答案(倍增搞)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <complex>
#include <algorithm>
#include <climits>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define
#define

using namespace std;
typedef long long ll;
struct node {int next, to, h; ll w;}e[B << 2];
int head[A], num;
void add(int fr, int to, ll w, int h) {
e[++num].next = head[fr];
e[num].to = to; e[num].w = w;
e[num].h = h; head[fr] = num;
}
struct Edge {
int a, b, h; ll w;
friend bool operator < (const Edge a, const Edge b) {return a.h > b.h;}
}p[B << 2];
int T, n, m, a, b, d, w[A], cnt, Q, k, s; ll c;
struct STA {
int id; ll val;
friend bool operator < (const STA a, const STA b) {return a.val > b.val;}
};
ll dis[A]; bool vis[A];
priority_queue<STA> q;
void dijkstra() {
memset(vis, 0, sizeof vis); memset(dis, 0x7f, sizeof dis);
q.push(STA{1, 0}); dis[1] = 0;
while (!q.empty()) {
int fr = q.top().id; q.pop();
if (vis[fr]) continue; vis[fr] = 1;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (dis[ca] > dis[fr] + e[i].w) {
dis[ca] = dis[fr] + e[i].w;
q.push(STA{ca, dis[ca]});
}
}
}
}
int f[A][21], fa[A], fat[A]; ll r[A];
int find(int x) {
if (fa[x] == x) return x;
else return fa[x] = find(fa[x]);
}
void dfs(int fr) {
r[fr] = dis[fr];
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (ca == fat[fr]) continue;
fat[ca] = fr;
dfs(ca);
r[fr] = min(r[fr], r[ca]);
}
}
ll ask(int v, int p) {
for (int i = 20; i >= 0; i--)
if (w[f[v][i]] > p) v = f[v][i];
return r[v];
}

int main(int argc, char const *argv[]) {
cin >> T;
while (T--) {
memset(head, 0, sizeof head); num = 0;
scanf("%d%d", &n, &m); cnt = n;
for (int i = 1; i <= m; i++) {
scanf("%d%d%lld%d", &a, &b, &c, &d);
add(a, b, c, d); add(b, a, c, d);
p[i] = Edge{a, b, d, c};
}
dijkstra();
// cout << "dis:"; for (int i = 1; i <= n; i++) cout << dis[i] << " "; puts("");
memset(head, 0, sizeof head); num = 0;
sort(p + 1, p + m + 1);
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= m; i++) {
int fx = find(p[i].a), fy = find(p[i].b);
if (fx == fy) continue;
++cnt; fa[cnt] = fa[fx] = fa[fy] = cnt; w[cnt] = p[i].h;
add(cnt, fx, 0, 0); add(fx, cnt, 0, 0);
add(cnt, fy, 0, 0); add(fy, cnt, 0, 0);
}
// cout << "cnt:" << cnt << endl;
dfs(cnt);
for (int i = 1; i <= cnt; i++) f[i][0] = fat[i];
// cout << "fa[i]:"; for (int i = 1; i <= cnt; i++) cout << f[i][0] << " "; puts("");
for (int j = 1; 1 << j <= cnt; j++)
for (int i = 1; i <= cnt; i++)
f[i][j] = f[f[i][j - 1]][j - 1];
// puts("f[i][j]:");
// for (int j = 1; 1 << j <= cnt; j++, puts(""))
// for (int i = 1; i <= cnt; i++)
// cout << f[i][j] << " ";
ll lastans = 0;
scanf("%d%d%d", &Q, &k, &s);
while (Q --> 0) {
scanf("%d%d", &a, &b);
a = (a + k * lastans - 1) % n + 1;
b = (b + k * lastans) % (s + 1);
// cout << "a, b:" << a << " " << b << endl;
printf("%lld\n", lastans = ask(a, b));
}
}
return 0;
}