[NOI 2018] 归程
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=5415
[算法]
对于v到1的1条合法路径 , 我们将其分为两段考虑
1. v -> u , 该路径上的最短边长大于等于P
2. u -> 1
显然 , 我们要求所有这样的路径中distu的最小值
不妨先用Dijkstra算法求出单源最短路 , 然后求出kruskal重构树
对于每组询问 , 将v在kruskal重构树上倍增 , 倍增到一个深度最小的点且该点的权值最小
那么答案即为这棵子树中dist的最小值
时间复杂度 : O(T(N+M+Q)logN)
[代码]
#include<bits/stdc++.h> using namespace std; const int N = 2e5 + 10; const int M = 4e5 + 10; const int MAXLOG = 20; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const ll inf = 1e18; struct info { int u , v , w; int h; } a[M]; struct edge { int to , nxt; } e[M << 1]; int n , m , tot , q , s , k , cnt; int head[N << 1] , val[N << 1] , father[N << 1][MAXLOG] , depth[N << 1] , fa[N << 1]; ll dist[N << 1] , mn[N << 1]; vector< pair<int , int> > G[N]; template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void dijkstra(int s) { static bool visited[N << 1]; priority_queue< pair<ll , int> , vector< pair<ll , int> > , greater< pair<ll , int> > > q; q.push(make_pair(0 , s)); for (int i = 1; i <= n; i++) { dist[i] = inf; visited[i] = false; } dist[s] = 0; while (!q.empty()) { int cur = q.top().second; q.pop(); if (visited[cur]) continue; visited[cur] = true; for (unsigned i = 0; i < G[cur].size(); i++) { int to = G[cur][i].first , w = G[cur][i].second; if (dist[cur] + w < dist[to]) { dist[to] = dist[cur] + w; q.push(make_pair(dist[to] , to)); } } } } inline bool cmp(info a , info b) { return a.h > b.h; } inline void dfs(int u , int par) { father[u][0] = par; depth[u] = depth[par] + 1; for (int i = 1; i < MAXLOG; i++) father[u][i] = father[father[u][i - 1]][i - 1]; if (!head[u]) // leaf { mn[u] = dist[u]; return; } mn[u] = inf; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != par) dfs(v , u); chkmin(mn[u] , mn[v]); } } inline int getroot(int x) { if (fa[x] == x) return x; else return fa[x] = getroot(fa[x]); } inline void addedge(int u , int v) { ++tot; e[tot] = (edge){v , head[u]}; head[u] = tot; } inline void kruskal() { int tot = 0; cnt = n; for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= m; i++) { int fu = getroot(a[i].u) , fv = getroot(a[i].v); if (fu != fv) { fa[fu] = fv; addedge(++cnt , fu); addedge(cnt , fv); val[cnt] = a[i].h; fa[fu] = fa[fv] = fa[cnt] = cnt; ++tot; } if (tot == n - 1) break; } dfs(cnt , 0); } int main() { int T; read(T); while (T--) { read(n); read(m); tot = 0; memset(head , 0 , sizeof(head)); for (int i = 1; i <= n; i++) G[i].clear(); for (int i = 1; i <= m; i++) { read(a[i].u); read(a[i].v); read(a[i].w); read(a[i].h); G[a[i].u].push_back(make_pair(a[i].v , a[i].w)); G[a[i].v].push_back(make_pair(a[i].u , a[i].w)); } sort(a + 1 , a + m + 1 , cmp); dijkstra(1); kruskal(); read(q); read(k); read(s); int lastans = 0; while (q--) { int v0 , p0; read(v0); read(p0); int v = (v0 + 1ll * k * lastans - 1) % n + 1 , p = (p0 + 1ll * k * lastans) % (s + 1); for (int i = MAXLOG - 1; i >= 0; i--) { if (depth[father[v][i]] > 0 && val[father[v][i]] > p) v = father[v][i]; } printf("%lld\n" , lastans = mn[v]); } } return 0; }