LOJ#2245 魔法森林

这道题以前zbtrs大佬给我讲过。但是我只知道思想,不知道要lct维护...

这个套路很常见。

题意:给你一个无向图,每条边有a,b两个权值。求1到n号点的一条路径,路径的权值是每条边的最大a与最大b之和。求可能的最小权值。无解输出-1。

解:有个很朴素的想法是爆搜......

有个很朴素(??)的想法,最后路径的a最大值一定是某条边的a,于是我们枚举这个a,每次把小于a的边都加进去,然后若1,n连通就跑b的最短路。这样就有50分了。

然后我们发现每次跑最短路的时间不可承受,如何优化呢?

我们肯定会在某一时刻加出环,然后我们发现这个环上的a的大小是无关紧要的,我们把环上b最大的边去掉,这样就是一棵树了。

然后用lct实行这个操作,时间复杂度mlog(n + m)。

注意这里没有点权,只有边权,而且边全都给出来了,我们就对于每个边新建一个点代表它就行了...具体看代码。

  1 // NOI 2014 mofa forest
  2 #include <cstdio>
  3 #include <algorithm>
  4 
  5 const int N = 50010, M = 100010, INF = 0x7f7f7f7f;
  6 
  7 inline void read(int &x) {
  8     char c = getchar();
  9     bool f = 0;
 10     while(c < '0' || c > '9') {
 11         if(c == '-') {
 12             f = 1;
 13         }
 14         c = getchar();
 15     }
 16     while(c >= '0' && c <= '9') {
 17         x = (x << 3) + (x << 1) + c - 48;
 18         c = getchar();
 19     }
 20     if(f) {
 21         x = -x;
 22     }
 23     return;
 24 }
 25 
 26 struct Edge {
 27     int u, v;
 28     int a, b;
 29     inline bool operator <(const Edge &d) const {
 30         if(a != d.a) {
 31             return a < d.a;
 32         }
 33         return b < d.b;
 34     }
 35 }edge[M];
 36 
 37 struct UFS {
 38     int fa[N + M];
 39 
 40     inline void clear() {
 41         for(int i = 1; i < N + M; i++) {
 42             fa[i] = i;
 43         }
 44         return;
 45     }
 46 
 47     UFS() {
 48         clear();
 49     }
 50 
 51     inline int find(int x) {
 52         if(fa[x] == x) {
 53             return x;
 54         }
 55         return fa[x] = find(fa[x]);
 56     }
 57 
 58     inline void merge(int x, int y) {
 59         fa[find(x)] = find(y);
 60         return;
 61     }
 62 
 63     inline bool check(int x, int y) {
 64         return find(x) == find(y);
 65     }
 66 }ufs;
 67 
 68 struct LCT {
 69     int val[N + M], fa[N + M], s[N + M][2], large[N + M], stk[N + M], t;
 70     bool rev[N + M];
 71 
 72     inline int no_root(int x) {
 73         return s[fa[x]][0] == x || s[fa[x]][1] == x;
 74     }
 75 
 76     inline void pushup(int x) {
 77         large[x] = x;
 78         if(val[large[x]] < val[large[s[x][0]]]) {
 79             large[x] = large[s[x][0]];
 80         }
 81         if(val[large[x]] < val[large[s[x][1]]]) {
 82             large[x] = large[s[x][1]];
 83         }
 84         return;
 85     }
 86 
 87     inline void pushdown(int x) {
 88         if(!rev[x]) {
 89             return;
 90         }
 91         if(s[x][0]) {
 92             rev[s[x][0]] ^= 1;
 93         }
 94         if(s[x][1]) {
 95             rev[s[x][1]] ^= 1;
 96         }
 97         std::swap(s[x][0], s[x][1]);
 98         rev[x] = 0;
 99         return;
100     }
101 
102     inline void rotate(int x) {
103         int y = fa[x];
104         int z = fa[y];
105         bool f = (s[y][1] == x);
106 
107         fa[x] = z;
108         if(no_root(y)) {
109             s[z][s[z][1] == y] = x;
110         }
111         s[y][f] = s[x][!f];
112         fa[s[x][!f]] = y;
113         s[x][!f] = y;
114         fa[y] = x;
115 
116         pushup(y);
117         pushup(x);
118         return;
119     }
120 
121     inline void splay(int x) {
122         int y = x;
123         stk[++t] = x;
124         while(no_root(y)) {
125             y = fa[y];
126             stk[++t] = y;
127         }
128         while(t) {
129             pushdown(stk[t]);
130             t--;
131         }
132         y = fa[x];
133         int z = fa[y];
134         while(no_root(x)) {
135             if(no_root(y)) {
136                 (s[z][1] == y) ^ (s[y][1] == x) ?
137                 rotate(x) : rotate(y);
138             }
139             rotate(x);
140             y = fa[x];
141             z = fa[y];
142         }
143         return;
144     }
145 
146     inline void access(int x) {
147         int y = 0;
148         while(x) {
149             splay(x);
150             s[x][1] = y;
151             pushup(x);
152             y = x;
153             x = fa[x];
154         }
155         return;
156     }
157 
158     inline int findroot(int x) {
159         access(x);
160         splay(x);
161         pushdown(x);
162         while(s[x][0]) {
163             x = s[x][0];
164             pushdown(x);
165         }
166         return x;
167     }
168 
169     inline void makeroot(int x) {
170         access(x);
171         splay(x);
172         rev[x] = 1;
173         return;
174     }
175 
176     inline void link(int x, int y) {
177         makeroot(x);
178         if(findroot(y) != x) {
179             fa[x] = y;
180         }
181         return;
182     }
183 
184     inline void cut(int x, int y) {
185         makeroot(x);
186         access(y);
187         splay(y);
188         if(s[y][0] == x && fa[x] == y && s[x][1] == 0) {
189             fa[x] = 0;
190             s[y][0] = 0;
191             pushup(y);
192         }
193         return;
194     }
195 
196     inline int getmax(int x, int y) {
197         makeroot(x);
198         access(y);
199         splay(y);
200         return large[y];
201     }
202 }lct;
203 
204 int main()  {
205     int n, m, ans = INF;
206     scanf("%d%d", &n, &m);
207     for(int i = 1; i <= m; i++) {
208         read(edge[i].u);
209         read(edge[i].v);
210         read(edge[i].a);
211         read(edge[i].b);
212     }
213     std::sort(edge + 1, edge + m + 1);
214     for(int i = 1; i <= m; i++) {
215         lct.val[i + n] = edge[i].b;
216     }
217 
218     for(int i = 1; i <= m; i++) {
219         int x = edge[i].u;
220         int y = edge[i].v;
221         //printf("%d - %d  a = %d  b = %d  
", x, y, edge[i].a, edge[i].b);
222         if(ufs.check(x, y)) {
223             int t = lct.getmax(x, y);
224             if(lct.val[t] > edge[i].b) {
225                 lct.cut(edge[t - n].u, t);
226                 lct.cut(edge[t - n].v, t);
227                 lct.link(x, i + n);
228                 lct.link(y, i + n);
229                 if(ufs.check(1, n)) {
230                     ans = std::min(ans, edge[i].a + lct.val[lct.getmax(1, n)]);
231                 }
232                 //printf("1 : ans = %d 
", ans);
233             }
234         }
235         else {
236             ufs.merge(x, y);
237             lct.link(x, i + n);
238             lct.link(y, i + n);
239             if(ufs.check(1, n)) {
240                 ans = std::min(ans, edge[i].a + lct.val[lct.getmax(1, n)]);
241                 //printf("2 : ans = %d 
", ans);
242             }
243         }
244     }
245     printf("%d", ans == INF ? -1 : ans);
246     return 0;
247 }
AC代码

update:前面15分是搜索,50分是枚举一条边,暴力维护生成树。70分是枚举a的取值,并查集维护。看代码吧。

  1 #include <bits/stdc++.h>
  2 
  3 const int N = 200010, INF = 0x3f3f3f3f;
  4 
  5 struct Edge {
  6     int nex, v, a, b, pre;
  7 }edge[N << 1]; int tp = 1;
  8 
  9 struct Node {
 10     int a, b, x, y;
 11     inline bool operator < (const Node &w) const {
 12         return a < w.a;
 13     }
 14 }node[N << 1];
 15 
 16 int e[N], n, m;
 17 std::multiset<int> st;
 18 
 19 inline void add(int x, int y, int a, int b) {
 20     tp++;
 21     edge[tp].v = y;
 22     edge[tp].a = a;
 23     edge[tp].b = b;
 24     edge[tp].nex = e[x];
 25     if(e[x]) edge[e[x]].pre = tp;
 26     e[x] = tp;
 27     return;
 28 }
 29 
 30 inline void del(int x, int i) {
 31     if(!edge[i].nex && e[x] == i) {
 32         e[x] = 0;
 33     }
 34     else if(!edge[i].nex) {
 35         edge[edge[i].pre].nex = 0;
 36     }
 37     else if(e[x] == i) {
 38         e[x] = edge[i].nex;
 39         edge[e[x]].pre = 0;
 40     }
 41     else {
 42         edge[edge[i].pre].nex = edge[i].nex;
 43         edge[edge[i].nex].pre = edge[i].pre;
 44     }
 45     return;
 46 }
 47 
 48 inline void Link() {
 49     for(int i = 1; i <= m; i++) {
 50         add(node[i].x, node[i].y, node[i].a, node[i].b);
 51         add(node[i].y, node[i].x, node[i].a, node[i].b);
 52     }
 53     return;
 54 }
 55 
 56 namespace bf {
 57     int ans = INF;
 58     bool vis[N];
 59     void DFS(int x, int a, int b) {
 60         if(x == n) {
 61             ans = std::min(ans, a + b);
 62             return;
 63         }
 64         vis[x] = 1;
 65         for(int i = e[x]; i; i = edge[i].nex) {
 66             int y = edge[i].v;
 67             if(vis[y]) continue;
 68             DFS(y, std::max(a, edge[i].a), std::max(b, edge[i].b));
 69         }
 70         vis[x] = 0;
 71         return;
 72     }
 73     inline void solve() {
 74         Link();
 75         DFS(1, 0, 0);
 76         if(ans == INF) ans = -1;
 77         printf("%d
", ans);
 78         return;
 79     }
 80 }
 81 
 82 namespace ufs {
 83     int fa[N];
 84     inline void init() {
 85         for(int i = 1; i <= n; i++) fa[i] = i;
 86         return;
 87     }
 88     int find(int x) {
 89         if(fa[x] == x) return x;
 90         return fa[x] = find(fa[x]);
 91     }
 92     inline void merge(int x, int y) {
 93         fa[find(x)] = find(y);
 94         return;
 95     }
 96     inline bool check(int x, int y) {
 97         return find(x) == find(y);
 98     }
 99 }
100 
101 namespace bf2 {
102     int Time, large, pos, vis[N];
103     bool DFS(int x, int t) {
104         if(x == t) return true;
105         vis[x] = Time;
106         for(int i = e[x]; i; i = edge[i].nex) {
107             int y = edge[i].v;
108             if(vis[y] == Time) continue;
109             if(DFS(y, t)) {
110                 if(large < edge[i].b) {
111                     large = edge[i].b;
112                     pos = i;
113                 }
114                 return true;
115             }
116         }
117         return false;
118     }
119     int getMax(int x) {
120         if(x == n) return 0;
121         vis[x] = Time;
122         for(int i = e[x]; i; i = edge[i].nex) {
123             int y = edge[i].v;
124             if(vis[y] == Time) continue;
125             int t = getMax(y);
126             if(t == -1) continue;
127             return std::max(t, edge[i].b);
128         }
129         return -1;
130     }
131     inline void solve() {
132         int ans = INF;
133         ufs::init();
134         for(int i = 1; i <= m; i++) {
135             int x = node[i].x, y = node[i].y;
136             if(ufs::check(x, y)) {
137                 large = -1;
138                 ++Time;
139                 DFS(x, y);
140                 if(large <= node[i].b) continue;
141                 del(edge[pos ^ 1].v, pos);
142                 del(edge[pos].v, pos ^ 1);
143                 add(x, y, node[i].a, node[i].b);
144                 add(y, x, node[i].a, node[i].b);
145             }
146             else {
147                 ufs::merge(x, y);
148                 add(x, y, node[i].a, node[i].b);
149                 add(y, x, node[i].a, node[i].b);
150             }
151             if(ufs::check(1, n)) {
152                 ++Time;
153                 int temp = getMax(1);
154                 ans = std::min(ans, node[i].a + temp);
155             }
156         }
157         if(ans == INF) ans = -1;
158         printf("%d
", ans);
159         return;
160     }
161 }
162 
163 namespace bf3 {
164     inline bool cmp(const Node &x, const Node &y) {
165         return x.b < y.b;
166     }
167     inline void solve() {
168         std::sort(node + 1, node + m + 1, cmp);
169         int ans = INF;
170         for(int lim = 1; lim <= 30; lim++) {
171             ufs::init();
172             int temp = INF;
173             for(int i = 1; i <= m; i++) {
174                 if(node[i].a > lim) {
175                     continue;
176                 }
177                 ufs::merge(node[i].x, node[i].y);
178                 if(ufs::check(1, n)) {
179                     temp = node[i].b;
180                     break;
181                 }
182             }
183             ans = std::min(ans, lim + temp);
184         }
185         if(ans == INF) ans = -1;
186         printf("%d
", ans);
187         return;
188     }
189 }
190 
191 namespace lct {
192     int fa[N], s[N][2], large[N], val[N], stk[N], top;
193     bool rev[N];
194     inline bool no_root(int x) {
195         return s[fa[x]][0] == x || s[fa[x]][1] == x;
196     }
197     inline void pushup(int x) {
198         large[x] = x;
199         if(s[x][0] && val[large[x]] < val[large[s[x][0]]]) {
200             large[x] = large[s[x][0]];
201         }
202         if(s[x][1] && val[large[x]] < val[large[s[x][1]]]) {
203             large[x] = large[s[x][1]];
204         }
205         return;
206     }
207     inline void pushdown(int x) {
208         if(rev[x]) {
209             if(s[x][0]) rev[s[x][0]] ^= 1;
210             if(s[x][1]) rev[s[x][1]] ^= 1;
211             std::swap(s[x][0], s[x][1]);
212             rev[x] = 0;
213         }
214         return;
215     }
216     inline void rotate(int x) {
217         int y = fa[x];
218         int z = fa[y];
219         bool f = (s[y][1] == x);
220 
221         fa[x] = z;
222         if(no_root(y)) {
223             s[z][s[z][1] == y] = x;
224         }
225         s[y][f] = s[x][!f];
226         if(s[x][!f]) {
227             fa[s[x][!f]] = y;
228         }
229         s[x][!f] = y;
230         fa[y] = x;
231 
232         pushup(y);
233         return;
234     }
235     inline void splay(int x) {
236         int y = x;
237         stk[top = 1] = y;
238         while(no_root(y)) {
239             y = fa[y];
240             stk[++top] = y;
241         }
242         while(top) {
243             pushdown(stk[top]);
244             top--;
245         }
246 
247         y = fa[x];
248         int z = fa[y];
249         while(no_root(x)) {
250             if(no_root(y)) {
251                 (s[z][1] == y) ^ (s[y][1] == x) ?
252                 rotate(x) : rotate(y);
253             }
254             rotate(x);
255             y = fa[x];
256             z = fa[y];
257         }
258         pushup(x);
259         return;
260     }
261     inline void access(int x) {
262         int y = 0;
263         while(x) {
264             splay(x);
265             s[x][1] = y;
266             pushup(x);
267             y = x;
268             x = fa[x];
269         }
270         return;
271     }
272     inline void make_root(int x) {
273         access(x);
274         splay(x);
275         rev[x] ^= 1;
276         return;
277     }
278     inline int find_root(int x) {
279         access(x);
280         splay(x);
281         while(s[x][0]) {
282             x = s[x][0];
283             pushdown(x);
284         }
285         splay(x);
286         return x;
287     }
288     inline void link(int x, int y) {
289         make_root(x);
290         fa[x] = y;
291         return;
292     }
293     inline void cut(int x, int y) {
294         make_root(x);
295         access(y);
296         splay(y);
297         fa[x] = s[y][0] = 0;
298         pushup(y);
299         return;
300     }
301     inline int ask(int x, int y) {
302         make_root(x);
303         access(y);
304         splay(y);
305         return large[y];
306     }
307 }
308 
309 int main() {
310     scanf("%d%d", &n, &m);
311     int largeA = -1;
312     for(int i = 1; i <= m; i++) {
313         scanf("%d%d%d%d", &node[i].x, &node[i].y, &node[i].a, &node[i].b);
314         largeA = std::max(largeA, node[i].a);
315     }
316     std::sort(node + 1, node + m + 1);
317     if(n <= 5 && m <= 10) {
318         bf::solve();
319         return 0;
320     }
321     if(n <= 5000 && m <= 10000) {
322         bf2::solve();
323         return 0;
324     }
325     if(largeA <= 30) {
326         bf3::solve();
327         return 0;
328     }
329     /// lct solve
330     int ans = INF;
331     ufs::init();
332     for(int i = 1; i <= m; i++) {
333         lct::val[n + i] = node[i].b;
334     }
335     for(int i = 1; i <= m; i++) {
336         int x = node[i].x, y = node[i].y;
337         if(ufs::check(x, y)){
338             int t = lct::ask(x, y);
339             if(lct::val[t] <= node[i].b) continue;
340             lct::cut(t, node[t - n].x);
341             lct::cut(t, node[t - n].y);
342             lct::link(x, n + i);
343             lct::link(y, n + i);
344         }
345         else {
346             lct::link(x, n + i);
347             lct::link(y, n + i);
348             ufs::merge(x, y);
349         }
350         if(ufs::check(1, n)) {
351             ans = std::min(ans, node[i].a + lct::val[lct::ask(1, n)]);
352         }
353     }
354     if(ans == INF) ans = -1;
355     printf("%d
", ans);
356     return 0;
357 }
AC代码
原文地址:https://www.cnblogs.com/huyufeifei/p/9750804.html