[NOI2018]归程

今年D1T1,平心而论,如果能想到kruskal重构树还是很简单的。

......苟屁啊!虽然跟其他的比是简单些,但是思维难度中上,代码难度中上,怎么看都很符合NOI T1啊。

本题还有可持久化并查集的做法,以高度为版本。我没有打......

言归正传,来看题。

给你一个无向图,每条边有高度和长度。每次询问,从点s出发,只能经过高度大于h的边所能到达的点中,距1号点最近的点的距离。强制在线。

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

首先,离线有65分,十分可观。我们把边和询问都按照高度排序。然后依次加入,并查集维护连通块内dis最小值。

克鲁斯卡尔重构树解法:

首先讲什么是克鲁斯卡尔重构树:说起来也蛮简单,就是你把边排序,加边的时候如果连通就不加,否则新建节点代表这个连通块,边的两端所在连通块的代表节点作为这个新节点的两个子节点。

这样你要查询高度h时dis min,只需维护一个节点所代表连通块内dis最小值即可。每次向上跳,可以发现一条链上的dis min单调不增。然后就倍增了,类似lca。

啊我到底在口胡什么。

  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行代码还行。

 

posted @ 2018-10-02 19:00  huyufeifei  阅读(253)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜