LOJ #2718. 「NOI2018」归程

#2718. 「NOI2018」归程

https://loj.ac/problem/2718

分析:

  首先按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 }

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/9354050.html