生活随笔
收集整理的這篇文章主要介紹了
luogu 4768
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
kruskal 重構樹
對于一張無向圖,我們在進行 kruskal 的過程中
每當合并兩個聯通塊時
新建虛擬節點 t
對于兩個聯通塊的根節點 fau,fav 連無向邊
(fau, t),(fav, t) 其中點 t 的點權為兩個聯通塊當前連邊的邊權
對于這道題
首先 dijkstra 處理所有點到1號點的最短路
然后按照邊的海拔進行降序排序
這樣做出重構樹之后
顯然對于點 u,它的所有子樹中的相關的邊的海拔(這里已經轉化為了虛擬節點的點權)都要大于該點的海拔
這樣的話
對于詢問二元組 x, h
倍增將 x 調到海拔最低且高于 h 的點處
此時 x 的子樹中dis[]的最小值即為此次詢問的結果
注意:在進行重構樹時
虛擬節點的dis[]每次可以取 min(dis[fau], dis[fav])
這樣就相當于dis[t]表示 t 的子樹中dis[]的最小值
省去了一遍 dfs
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
const int N = 4e5 +
10, oo = 1e9 +
7;struct Node {int u, v, len, high, nxt;
} E[N], G[N <<
2], Edge[N <<
1];
struct Node_ {int u, dis_;inline bool operator < (
const Node_ a)
const {
return dis_ >
a.dis_;}
};int head_1[N], head_2[N <<
1], now;
int dis[N <<
1];
bool vis[N];
int fa[N <<
1];
int n, m;
int High[N <<
1];
int f[N <<
1][
30];
int deep[N <<
1];#define gc getchar()
inline int read() {int x =
0;char c =
gc;while(c <
'0' || c >
'9') c =
gc;while(c >=
'0' && c <=
'9') x = x *
10 + c -
'0', c =
gc;return x;
}int Get(
int x) {
return fa[x] == x ? x : fa[x] =
Get(fa[x]);}
inline bool Cmp(Node a, Node b) {
return a.high >
b.high;}
void Dfs(
int u,
int fa) {
for(
int i = head_2[u]; ~ i; i = G[i].nxt)
if(G[i].v != fa) f[G[i].v][
0] =
u, Dfs(G[i].v, u);}
inline int Jump(
int X,
int H) {
for(
int i =
20; i >=
0; i --)
if(f[X][i] && High[f[X][i]] > H) X = f[X][i];
return X;}
inline void Add_Edge(
int u,
int v,
int Len) {Edge[++ now].v = v; Edge[now].len = Len; Edge[now].nxt = head_1[u]; head_1[u] =
now;}
inline void Add_G(
int u,
int v) {G[++ now].v = v; G[now].nxt = head_2[u]; head_2[u] =
now;}
inline void Pre() {
for(
int i =
1; i <=
20; i ++)
for(
int j =
1; j <= (n *
2 -
1); j ++) f[j][i] = f[f[j][i -
1]][i -
1];}inline void Dijkstra() {for(
int i =
1; i <= n; i ++) dis[i] =
oo;for(
int i =
1; i <= n; i ++) vis[i] =
0;priority_queue <Node_>
Q;Q.push((Node_) {1,
0});dis[1] =
0;while(!
Q.empty()) {Node_ topp =
Q.top();Q.pop();if(vis[topp.u])
continue;vis[topp.u] =
1;for(
int i = head_1[topp.u]; ~ i; i =
Edge[i].nxt)if(dis[Edge[i].v] > dis[topp.u] +
Edge[i].len) {dis[Edge[i].v] = dis[topp.u] +
Edge[i].len;Q.push((Node_) {Edge[i].v, dis[Edge[i].v]});}}
}inline void Kruskal() {sort(E +
1, E + m +
1, Cmp);for(
int i =
1; i <= (n <<
1); i ++) fa[i] =
i;for(
int i =
1; i <= (n <<
1); i ++) head_2[i] = -
1;int cnt =
n;now =
0;for(
int i =
1; i <= m; i ++
) {if(cnt == n *
2 -
1)
break;int u = E[i].u, v = E[i].v, fau = Get(u), fav =
Get(v);if(fau !=
fav) {fa[fau] = fa[fav] = ++
cnt;High[cnt] =
E[i].high;dis[cnt] =
min(dis[fau], dis[fav]);Add_G(fau, cnt), Add_G(cnt, fau), Add_G(fav, cnt), Add_G(cnt, fav);}}
}int main() {for(
int T = read(); T; T --
) {memset(f, 0,
sizeof f);n = read(), m = read(); now =
0;for(
int i =
1; i <= n; i ++) head_1[i] = -
1;for(
int i =
1; i <= m; i ++
) {int u = read(), v = read(), Len = read(), high =
read();Add_Edge(u, v, Len), Add_Edge(v, u, Len);E[i] =
(Node) {u, v, Len, high};}Dijkstra(), Kruskal(), Dfs(2 * n -
1,
0), Pre();int Q = read(), K = read(), S = read(), Lastans =
0;for(; Q; Q --
) {int X = (read() + K * Lastans -
1) % n +
1, H = (read() + K * Lastans) % (S +
1);Lastans = dis[Jump(X, H)]; cout << Lastans <<
"\n";}}return 0;
} ?
轉載于:https://www.cnblogs.com/shandongs1/p/9497615.html
總結
以上是生活随笔為你收集整理的luogu 4768的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。