LOJ #2718. 「NOI2018」归程
#2718. 「NOI2018」归程
分析:
首先按h建立kruskal重构树,每个节点保存新加入这条边的高度。另记录一个数组dis,表示在重构树中,以这个点为根的子树中,距离1号点最小的距离是多少。
查询所有大于某个值得边,就是在kruskal重构树,从下往上找到第一个大于这个值的点。然后这个点的dis就是答案。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline int read() { 6 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 7 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 8 } 9 10 const int N = 200100; 11 const int M = 400100; 12 const LL Linf = 1e18; 13 const int inf = 1e9; 14 15 int n, m, CntNode, TOT, Enum; 16 17 struct Heap{ 18 int u; LL w; 19 Heap() {} 20 Heap(int a,LL b) {u = a, w = b;} 21 bool operator < (const Heap &A) const { 22 return w > A.w; // 小根堆 23 } 24 }; 25 int head[N<<1], nxt[M<<1], to[M<<1]; 26 LL len[M<<1], dis[N<<1]; // dis开两倍空间,下面会用到 27 bool vis[N]; 28 priority_queue<Heap>q; 29 30 void Dijkstra(int S) { 31 for (int i=1; i<=n; ++i) 32 dis[i] = Linf, vis[i] = false; 33 dis[S] = 0; 34 q.push(Heap(S,0)); 35 while (!q.empty()) { 36 int u = q.top().u; q.pop(); 37 if (vis[u]) continue; 38 vis[u] = true; 39 for (int i=head[u]; i; i=nxt[i]) { 40 int v = to[i]; 41 if (dis[v] > dis[u] + len[i]) { 42 dis[v] = dis[u] + len[i]; 43 q.push(Heap(v,dis[v])); 44 } 45 } 46 } 47 } 48 49 struct Edge{ 50 int u, v, h; 51 bool operator < (const Edge &A) const { 52 return h > A.h; 53 } 54 }e[M]; 55 int val[N<<1], fa[N<<1], f[N<<1][21]; 56 57 int find(int x) { 58 return x == fa[x] ? x : fa[x] = find(fa[x]); 59 } 60 void Kruskal() { 61 sort(e+1, e+m+1); 62 for (int i=1; i<=n+n; ++i) fa[i] = i; 63 int Count_Edge = 0; 64 for (int i=1; i<=m; ++i) { 65 int u = find(e[i].u), v = find(e[i].v); 66 if (u == v) continue; 67 val[++CntNode] = e[i].h; 68 fa[u] = fa[v] = CntNode; 69 f[u][0] = CntNode, f[v][0] = CntNode; 70 dis[CntNode] = min(dis[v], dis[u]); 71 if ((++Count_Edge) == n - 1) break; 72 } 73 } 74 75 void add_edge(int u,int v,int w,int h) { 76 ++Enum; to[Enum] = v; len[Enum] = w; nxt[Enum] = head[u]; head[u] = Enum; 77 ++Enum; to[Enum] = u; len[Enum] = w; nxt[Enum] = head[v]; head[v] = Enum; 78 ++TOT; e[TOT].u = u; e[TOT].v = v; e[TOT].h = h; 79 } 80 void init() { 81 TOT = Enum = n = m = CntNode = 0; 82 memset(head, 0, sizeof(head)); 83 memset(f, 0, sizeof(f)); 84 } 85 void solve() { 86 init(); 87 n = read(),m = read(),CntNode = n; 88 for (int i=1; i<=m; ++i) { 89 int u = read(), v = read(), w = read(), h = read(); 90 add_edge(u, v, w, h); 91 } 92 Dijkstra(1); 93 Kruskal(); 94 for (int j=1; j<=20; ++j) 95 for (int i=1; i<=CntNode; ++i) 96 f[i][j] = f[f[i][j-1]][j-1]; 97 98 LL Q = read(), K = read(), S = read(); 99 LL last = 0; 100 while (Q--) { 101 int v = read(), p = read(); 102 v = (v + K * last - 1) % n + 1; 103 p = (p + K * last) % (S + 1); //-- 104 for (int j=20; j>=0; --j) 105 if (f[v][j] && val[f[v][j]] > p) v = f[v][j]; 106 107 printf("%lld\n",last=dis[v]); 108 } 109 } 110 111 int main () { 112 freopen("return.in","r",stdin); 113 freopen("return.out","w",stdout); 114 int Case = read(); 115 while (Case --) solve(); 116 return 0; 117 }