[NOI2018]歸程

今年D1T1,平心而論,若是能想到kruskal重構樹仍是很簡單的。ide

......苟屁啊!雖然跟其餘的比是簡單些,可是思惟難度中上,代碼難度中上,怎麼看都很符合NOI T1啊。spa

本題還有可持久化並查集的作法,以高度爲版本。我沒有打......code

言歸正傳,來看題。blog

給你一個無向圖,每條邊有高度和長度。每次詢問,從點s出發,只能通過高度大於h的邊所能到達的點中,距1號點最近的點的距離。強制在線。排序

n<=200000,m<=400000,q<=400000string

首先,離線有65分,十分可觀。咱們把邊和詢問都按照高度排序。而後依次加入,並查集維護連通塊內dis最小值。it

克魯斯卡爾重構樹解法:io

首先講什麼是克魯斯卡爾重構樹:提及來也蠻簡單,就是你把邊排序,加邊的時候若是連通就不加,不然新建節點表明這個連通塊,邊的兩端所在連通塊的表明節點做爲這個新節點的兩個子節點。event

這樣你要查詢高度h時dis min,只需維護一個節點所表明連通塊內dis最小值便可。每次向上跳,能夠發現一條鏈上的dis min單調不增。而後就倍增了,相似lca。class

啊我到底在口胡什麼。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <queue>
  5 
  6 const int N = 200010, INF = 0x7f7f7f7f;
  7 
  8 struct Edge_1 {
  9     int v, len, nex;
 10 }edge_1[N << 2]; int top_1; // for dijkstra
 11 
 12 struct POI {
 13     int id, dis;
 14     inline bool operator <(const POI &d) const {
 15         return dis > d.dis;
 16     }
 17     POI(int a, int b) {
 18         id = a;
 19         dis = b;
 20     }
 21 }; // for dijkstra
 22 
 23 struct Edge_2 {
 24     int u, v, h;
 25     inline bool operator <(const Edge_2 &d) const {
 26         return h > d.h;
 27     }
 28 }edge_2[N << 1]; int top_2; // for sort kruskal
 29 
 30 struct UFS {
 31     int fa[N * 3];
 32     inline void clear() {
 33         for(int i = 1; i < N * 3; i++) {
 34             fa[i] = i;
 35         }
 36         return;
 37     }
 38     UFS() {
 39         clear();
 40     }
 41     int find(int x) {
 42         if(fa[x] == x) {
 43             return x;
 44         }
 45         return fa[x] = find(fa[x]);
 46     }
 47     inline void merge(int x, int y) { // x <- y
 48         fa[find(y)] = find(x);
 49         return;
 50     }
 51 }ufs;
 52 
 53 int e[N], dis[N * 3]; // for dijkstra
 54 int fa[N * 3][21], tot, h[N * 3]; // for kruskal
 55 
 56 inline void add_1(int x, int y, int z) {
 57     top_1++;
 58     edge_1[top_1].v = y;
 59     edge_1[top_1].len = z;
 60     edge_1[top_1].nex = e[x];
 61     e[x] = top_1;
 62     return;
 63 }
 64 
 65 inline void add_2(int x, int y, int z) {
 66     top_2++;
 67     edge_2[top_2].u = x;
 68     edge_2[top_2].v = y;
 69     edge_2[top_2].h = z;
 70     return;
 71 }
 72 
 73 inline void clear() {
 74     top_1 = 0;
 75     top_2 = 0;
 76     memset(e, 0, sizeof(e));
 77     ufs.clear();
 78     return;
 79 }
 80 
 81 inline void dijkstra() {
 82     std::priority_queue<POI> Q;
 83     memset(dis, 0x3f, sizeof(dis));
 84     dis[1] = 0;
 85     Q.push(POI(1, 0)); // POI(id, dis)
 86     while(!Q.empty()) {
 87         while(!Q.empty() && dis[Q.top().id] != Q.top().dis) {
 88             Q.pop();
 89         }
 90         if(Q.empty()) {
 91             break;
 92         }
 93         int x = Q.top().id;
 94         Q.pop();
 95         for(int i = e[x]; i; i = edge_1[i].nex) {
 96             int y = edge_1[i].v;
 97             if(dis[y] > dis[x] + edge_1[i].len) {
 98                 dis[y] = dis[x] + edge_1[i].len;
 99                 Q.push(POI(y, dis[y]));
100             }
101         }
102     }
103     return;
104 }
105 
106 inline void add(int p) {
107     int x = ufs.find(edge_2[p].u);
108     int y = ufs.find(edge_2[p].v);
109     if(x == y) {
110         return;
111     }
112     ++tot;
113     fa[x][0] = tot;
114     fa[y][0] = tot;
115     ufs.merge(tot, x);
116     ufs.merge(tot, y);
117     h[tot] = edge_2[p].h;
118     dis[tot] = std::min(dis[x], dis[y]);
119     return;
120 }
121 
122 inline int solve(int x, int high) {
123     int t = 20;
124     while(t >= 0) {
125         if(h[fa[x][t]] > high) {
126             x = fa[x][t];
127         }
128         t--;
129     }
130     return dis[x];
131 }
132 
133 int main() {
134     int T;
135     scanf("%d", &T);
136     while(T--) {
137         int n, m;
138         scanf("%d%d", &n, &m);
139         tot = n;
140         h[0] = -1;
141         for(int i = 1, x, y, z, w; i <= m; i++) {
142             scanf("%d%d%d%d", &x, &y, &z, &w);
143             add_1(x, y, z);
144             add_1(y, x, z);
145             add_2(x, y, w);
146         }
147 
148         // prework
149         dijkstra();
150         std::sort(edge_2 + 1, edge_2 + m + 1);
151         for(int i = 1; i <= m; i++) {
152             add(i);
153         }
154         for(int i = 1; i <= 20; i++) {
155             for(int x = 1; x <= tot; x++) {
156                 fa[x][i] = fa[fa[x][i - 1]][i - 1];
157             }
158         }
159 
160         int q, k, s, op, high, la = 0;
161         scanf("%d%d%d", &q, &k, &s);
162         while(q--) {
163             scanf("%d%d", &op, &high);
164             op = (op + k * la - 1) % n + 1;
165             high = (high + k * la) % (s + 1);
166             la = solve(op, high);
167             printf("%d\n", la);
168         }
169         clear();
170     }
171     return 0;
172 }
AC代碼

170行代碼還行。

相關文章
相關標籤/搜索