洛谷 P4768 [NOI2018] 歸程
阿新 • • 發佈:2021-10-12
Description
Solution
\(Kruskal\) 重構樹好題。
我們先按照水位 \(a\),建 \(Kruskal\) 重構樹。具體來講:按水位從高到低排序,每次選出剩餘邊中水位最高的一條邊插入到樹中,這樣就建成了一個小根堆。
然後我們再來考慮詢問。
對於一個水位線 \(p\),若 \(p < Kruskal\) 重構樹上的點 \(x\) 的水位,那麼在以 \(x\) 為根的子樹中,開車是可以隨意通行的,對答案沒有貢獻。
若 \(p > t[x].dep\) 且 \(p < t[fa[x]].dep\),那麼它就不得不在點 \(fa[x]\) 下車,所以對答案的貢獻就是從 \(fa[x]\)
那這個距離該如何算呢?
這個很簡單,只需要提前跑個 \(dijkstra\) 堆優化預處理一下即可,千萬千萬千萬不要使用 \(spfa\) (逃。
我們對於一組詢問 \(v\ p\),找到上述的 \(x\) 節點即可。
現在的問題就是如何找到這樣的節點,我們考慮倍增,倍增向上跳(就是個板子),具體見程式碼。
Code
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #define INF 0x3f3f3f3f using namespace std; inline int read(){ int x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x; } const int N = 4e5 + 10; int T, n, m, last; struct node{ int u, v, l, a, nxt; bool operator < (const node &b) const{ return a > b.a; } }e[N << 1], tmp[N << 1], edge[N << 1]; int head[N], tot, dis[N]; struct heap{ int x, dis; bool operator < (const heap &b) const{ return dis > b.dis; } }; int f[N], cnt; inline void Add(int x, int y, int z){ edge[++tot].v = y, edge[tot].l = z, edge[tot].nxt = head[x]; head[x] = tot; } inline void dijkstra(){ priority_queue <heap> q; memset(dis, 0x3f, sizeof(dis)); dis[1] = 0; q.push((heap){1, 0}); while(!q.empty()){ heap now = q.top(); q.pop(); int x = now.x; if(dis[x] < now.dis) continue; for(int i = head[x]; i; i = edge[i].nxt){ int y = edge[i].v; if(dis[y] > dis[x] + edge[i].l){ dis[y] = dis[x] + edge[i].l; q.push((heap){y, dis[y]}); } } } } inline int find(int x){ return f[x] == x ? x : f[x] = find(f[x]); } inline void add(int x, int y){ edge[++tot].v = y, edge[tot].nxt = head[x]; head[x] = tot; } inline void kruskal(){ sort(e + 1, e + 1 + m); for(int i = 1; i <= n; i++) f[i] = i; cnt = n; int num = 0; for(int i = 1; i <= m; i++){ int fu = find(e[i].u), fv = find(e[i].v); if(fu != fv){ num++; tmp[++cnt].a = e[i].a; f[fu] = f[fv] = f[cnt] = cnt; add(cnt, fu), add(cnt, fv); } if(num == n - 1) break; } } int fa[N][20], dep[N]; inline void dfs(int x, int p){ dep[x] = dep[p] + 1, fa[x][0] = p; for(int i = 1; i <= 19; i++) fa[x][i] = fa[fa[x][i - 1]][i - 1]; for(int i = head[x]; i; i = edge[i].nxt){ int y = edge[i].v; dfs(y, x); tmp[x].l = min(tmp[x].l, tmp[y].l); } } inline int query(int x, int y){ for(int i = 19; i >= 0; i--) if(dep[x] - (1 << i) > 0 && tmp[fa[x][i]].a > y) x = fa[x][i]; return tmp[x].l; } inline void solve(){ kruskal(); dfs(cnt, 0); int q = read(), k = read(), s = read(); while(q--){ int x = (k * last + read() - 1) % n + 1, y = (k * last + read()) % (s + 1); printf("%d\n", last = query(x, y)); } } inline void init(){ memset(head, 0, sizeof(head)); memset(fa, 0, sizeof(fa)); memset(f, 0, sizeof(f)); memset(tmp, 0, sizeof(tmp)); memset(edge, 0, sizeof(edge)); last = tot = 0; } int main(){ T = read(); while(T--){ init(); n = read(), m = read(); for(int i = 1; i <= m; i++){ e[i].u = read(), e[i].v = read(), e[i].l = read(), e[i].a = read(); Add(e[i].u, e[i].v, e[i].l), Add(e[i].v, e[i].u, e[i].l); } dijkstra(); for(int i = 1; i <= n; i++) tmp[i].l = dis[i]; for(int i = n + 1; i <= (n << 1); i++) tmp[i].l = INF; memset(head, 0, sizeof(head)), tot = 0; solve(); } }
End
本文來自部落格園,作者:{xixike},轉載請註明原文連結:https://www.cnblogs.com/xixike/p/15395800.html