[BZOJ2594] [Wc2006]水管局长数据加强版(LCT + kruskal + 离线)

传送门

WC这个题真是丧心病狂啊,就是想学习一下怎么处理边权,给我来了这么一个破题!

ORZ hzwer 临摹黄学长代码233 但还是复杂的一匹

理一下思路吧

题目大意:给定一个无向图,多次删除图中的某一条边,求两点间路径最大值的最小值

求两点间的路径最大值的最小值的话,可以求最小生成树,那么这个值就是最小生成树上两点间路径上的最大值

但是题目要求是删除边,LCT维护最小生成树不支持删边操作,那么就离线处理,倒着加边,用LCT维护。

就是这个离线处理是最恶心的。

来说说如何处理边权,把边也抽象成点,那么这个点就和原来边所连的两个点相连,其中边抽象成的点点权为边权,所连接的两个点点权为 0

给边从小到大排序,那么边所抽象成的点的序号即为 边的序号 + n (n 为原来点的个数)

然后再将边按照它所连的两个点为关键字排序,二分查找确定所删除的边的序号。

再按照从小到大的顺序再排回来,跑 kruskal,依次添加没有被删除的边

最后从后往前处理询问,添加一条边的时候先判断两端点是否连通(当然此题不必,因为题目中说:任何时候我们考虑的水管网络都是连通的,即从任一结点A必有至少一条水管路径通往任一结点B。。所以肯定连通)

然后找出两点间路径边权的最大的,判断最大的边权是否大于要加入的边的边权,如果大于,就删除这条边,连接新边,否则就不加入(维护最小生成树)

具体细节看代码

——代码

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #define N 1500005
  6 #define get(x) (son[f[x]][1] == (x))
  7 #define swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
  8 #define isroot(x) (son[f[x]][0] ^ (x) && son[f[x]][1] ^ (x))
  9
 10 int n, m, Q, tot;
 11 int mx[N], rev[N], fa[N], f[N], val[N], son[N][2], s[N];
 12
 13 struct node
 14 {
 15     int x, y, z, id;
 16     bool d;
 17 }e[N];
 18
 19 struct ask
 20 {
 21     int f, x, y, ans, id;
 22 }q[N];
 23
 24 inline int read()
 25 {
 26     int x = 0, f = 1;
 27     char ch = getchar();
 28     for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
 29     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
 30     return x * f;
 31 }
 32
 33 inline bool cmp1(node x, node y)
 34 {
 35     return x.z < y.z;
 36 }
 37
 38 inline bool cmp2(node x, node y)
 39 {
 40     return x.x < y.x || (x.x == y.x && x.y < y.y);
 41 }
 42
 43 inline bool cmp3(node x, node y)
 44 {
 45     return x.id < y.id;
 46 }
 47
 48 inline int getf(int x)
 49 {
 50     return x == fa[x] ? x : fa[x] = getf(fa[x]);
 51 }
 52
 53 inline int find(int x, int y)
 54 {
 55     int l = 1, r = m, mid;
 56     while(l <= r)
 57     {
 58         mid = (l + r) >> 1;
 59         if(e[mid].x < x || (e[mid].x == x && e[mid].y < y)) l = mid + 1;
 60         else if(e[mid].x == x && e[mid].y == y) return mid;
 61         else r = mid - 1;
 62     }
 63 }
 64
 65 inline void update(int x)
 66 {
 67     if(x)
 68     {
 69         mx[x] = x;
 70         if(son[x][0] && val[mx[son[x][0]]] > val[mx[x]]) mx[x] = mx[son[x][0]];
 71         if(son[x][1] && val[mx[son[x][1]]] > val[mx[x]]) mx[x] = mx[son[x][1]];
 72     }
 73 }
 74
 75 inline void pushdown(int x)
 76 {
 77     if(x && rev[x])
 78     {
 79         swap(son[x][0], son[x][1]);
 80         if(son[x][0]) rev[son[x][0]] ^= 1;
 81         if(son[x][1]) rev[son[x][1]] ^= 1;
 82         rev[x] = 0;
 83     }
 84 }
 85
 86 inline void rotate(int x)
 87 {
 88     int old = f[x], oldf = f[old], wh = get(x);
 89
 90     if(!isroot(old))
 91         son[oldf][get(old)] = x;
 92     f[x] = oldf;
 93
 94     son[old][wh] = son[x][wh ^ 1];
 95     f[son[old][wh]] = old;
 96
 97     son[x][wh ^ 1] = old;
 98     f[old] = x;
 99
100     update(old);
101     update(x);
102 }
103
104 inline void splay(int x)
105 {
106     int i, fat, t = 0;
107     s[++t] = x;
108     for(i = x; !isroot(i); i = f[i]) s[++t] = f[i];
109     for(i = t; i; i--) pushdown(s[i]);
110     for(; !isroot(x); rotate(x))
111         if(!isroot(fat = f[x]))
112             rotate(get(x) ^ get(fat) ? x : fat);
113 }
114
115 inline void access(int x)
116 {
117     for(int t = 0; x; t = x, x = f[x]) splay(x), son[x][1] = t, update(x);
118 }
119
120 inline void reverse(int x)
121 {
122     access(x);
123     splay(x);
124     rev[x] ^= 1;
125 }
126
127 inline void cut(int x, int y)
128 {
129     reverse(x);
130     access(y);
131     splay(y);
132     son[y][0] = f[x] = 0;
133     update(y);
134 }
135
136 inline void link(int x, int y)
137 {
138     reverse(x);
139     f[x] = y;
140     access(x);
141 }
142
143 inline int query(int x, int y)
144 {
145     reverse(x);
146     access(y);
147     splay(y);
148     return mx[y];
149 }
150
151 int main()
152 {
153     int i, j, k, t, x, y, fx, fy;
154     n = read();
155     m = read();
156     Q = read();
157     for(i = 1; i <= n; i++) fa[i] = i;
158     for(i = 1; i <= m; i++)
159     {
160         e[i].x = read();
161         e[i].y = read();
162         e[i].z = read();
163         if(e[i].x > e[i].y) swap(e[i].x, e[i].y);
164     }
165     std::sort(e + 1, e + m + 1, cmp1);
166     for(i = 1; i <= m; i++)
167     {
168         e[i].id = i;
169         val[n + i] = e[i].z;
170         mx[n + i] = n + i;
171     }
172     std::sort(e + 1, e + m + 1, cmp2);
173     for(i = 1; i <= Q; i++)
174     {
175         q[i].f = read();
176         q[i].x = read();
177         q[i].y = read();
178         if(q[i].x > q[i].y) swap(q[i].x, q[i].y);
179         if(q[i].f == 2)
180         {
181             t = find(q[i].x, q[i].y);
182             e[t].d = 1;
183             q[i].id = e[t].id;
184         }
185     }
186     std::sort(e + 1, e + m + 1, cmp3);
187     for(i = 1; i <= m; i++)
188         if(!e[i].d)
189         {
190             x = e[i].x;
191             y = e[i].y;
192             fx = getf(x);
193             fy = getf(y);
194             if(fx ^ fy)
195             {
196                 fa[fx] = fy;
197                 link(x, i + n);
198                 link(y, i + n);
199                 tot++;
200                 if(tot == n - 1) break;
201             }
202         }
203     for(i = Q; i; i--)
204     {
205         if(q[i].f == 1) q[i].ans = val[query(q[i].x, q[i].y)];
206         else
207         {
208             x = q[i].x;
209             y = q[i].y;
210             k = q[i].id;
211             t = query(x, y);
212             if(e[k].z < val[t])
213             {
214                 cut(e[t - n].x, t);
215                 cut(e[t - n].y, t);
216                 link(x, k + n);
217                 link(y, k + n);
218             }
219         }
220     }
221     for(i = 1; i <= Q; i++)
222         if(q[i].f == 1)
223             printf("%d\n", q[i].ans);
224     return 0;
225 }

时间: 2024-08-05 08:26:04

[BZOJ2594] [Wc2006]水管局长数据加强版(LCT + kruskal + 离线)的相关文章

[bzoj2594][Wc2006]水管局长数据加强版

论蒟蒻的自我修养T_T.. 和noi2014魔法森林基本一样...然而数据范围大得sxbk...100w你告诉我(n+m)log(n+m)可过?[掀桌] 蒟蒻又蠢了..复杂度应该是O((n+q)log(n+m))吧.. 一开始数组开太小re了两发(要开到maxn+maxm),然后又开太大mle一发,然后无限tle...把记录类型全改成数组还是tle.... 最后把非lct部分改得和黄学长全部一样终于20+s卡过去了......... 然后发现自己原来是有个地方写萎了..一开始把没被删的边做kru

BZOJ 2594: [Wc2006]水管局长数据加强版(kruskal + LCT)

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

沉迷Link-Cut tree无法自拔之:[BZOJ2594][Wc2006]水管局长数据加强版

来自蒟蒻 \(Hero \_of \_Someone\) 的 \(LCT\) 学习笔记 $ $ 这应该算是道套路题吧, 如果将图中的边转换成点, 再将边权变点权, 就可以用 \(LCT\) 来维护了 这道题的基本做法就是, 用 \(LCT\) 来动态地维护最小生成树, 如果这样做的话, 题目中要求的删边操作就不太好搞, 但是既然只有删边操作的话, 我们就可以考虑离线处理, 将不会被删除的边先加进图中跑 \(Kruskal\) , 然后化删边为添边, 倒着来处理每一组询问. $ $ 此外, 用 \

BZOJ 2594 [Wc2006]水管局长数据加强版 LCT

题意:链接 方法: LCT 解析: 搞了一个上午加1个小时的题,TM最后大错误居然是排序元素太多排不回原来的样子! 我要重新学排序! 这题是用LCT维护动态最小生成树,但是最小生成树上删边应该是做不到的,所以我们可以离线操作,之后先把所有该删的边删了然后倒着搞所有询问,这样删边就变成了加边,之后询问就是x到y路径上的最大边权. 图是动态的,所以想到LCT,但是LCT不能搞最大边权怎么办! 把每个边看做一个点. 假设这是第i个边,那么把他看做第i+n个点. 显然点权就是边权,然后将这个边连接的两个

【BZOJ 2594】 [Wc2006]水管局长数据加强版

2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MB Submit: 1138  Solved: 364 [Submit][Status] Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等

bzoj 2594: [Wc2006]水管局长数据加强版 动态树

2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MBSubmit: 934  Solved: 291[Submit][Status] Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径

BZOJ_2594_[Wc2006]水管局长数据加强版_LCT

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

【bzoj2594】[Wc2006]水管局长数据加强版

真是神题 当时调了几天没调出来 后来没管了 当时把fread去掉就TLE,加上就RE 一直在底下跟网上的程序拍,尝试各种优化常数都没用 拍出几组不一样的,发现我是对的,醉了,网上那个是怎么过的 记一下这蛋疼的代码 1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstdio> 6 #include<ma

BZOJ 2594 Wc2006 水管局长数据加强版 Link-Cut-Tree

题目大意:给定一个无向图,多次删除某条边,多次查询两点之间路径上边权最大值的最小值 Link-Cut-Tree维护动态最小生成树 首先倒着做 将所有被删除的边标记(找边我用的排序+二分) 将没标记的边跑一遍Kruskal 求出最小生成树 然后每次加边和查询正常维护即可 LInk-Cut-Tree一气呵成写完,Kruskal尼玛写挂了-- 居然忘记把并查集连边 这我也是醉了 顺便吐槽一下题干上给的读入优化真尼玛弱--自己随便写一个都可以优化到RANK前十-- #include<cstdio> #