[BZOJ 2594] [Wc2006]水管局长数据加强版 【LCT】
题目链接:BZOJ - 2594
题目分析
这道题如果没有删边的操作,那么就是 NOIP2013 货车运输,求两点之间的一条路径,使得边权最大的边的边权尽量小。
那么,这条路径就是最小生成树上这两点之间的路径。
然而现在有了删边操作,我们就需要一直维护当前的最小生成树。
删边然后维护 MST 还是不会做的,但是加边维护 MST 就可以用 LCT 来做了。于是,我们将询问和操作都记录下来,离线倒着做,就变成加边了。
加边维护 MST 的做法:
对于新加的一条边 (u, v, w) ,我们先求出现有 MST 中 u 到 v 的路径中,边权最大的边,如果这条边权最大的边的边权大于 w ,我们就将这条边删掉,将新加的边连上,加入 MST 。
否则,我们就忽略新加的这条边。
怎样处理边呢?我们把边看做和两个端点分别相连的一个点,即如果有一条边 (u, v) ,标号为 i ,那么我们就是连边 u -> i -> v ,就可以用 LCT 做了。
技巧:Splay 中一个节点就维护它的子树中边权最大的边的标号就可以了。
写代码时出现的错误:新加入一条边 (u, v, w) 时,发现现有 MST u 到 v 的路径上边权最大的边的边权 > w,需要删掉这条边,然后这条边是 T[t] ,t 是提取出的 u 到 v 的路径的 Splay 的根,
于是我 Cut(u, T[t]); Cut(v, T[t]); 然后就...就 0 分了。因为第一个 Cut 做完之后 T[t] 就改变了啊!!需要先记录下来然后再做两次 Cut !
代码
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath> using namespace std; inline void Read(int &Num)
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
Num = c - '0'; c = getchar();
while (c >= '0' && c <= '9')
{
Num = Num * 10 + c - '0';
c = getchar();
}
} const int MaxN = 100000 + 5, MaxM = 1000000 + 5, MaxT = 1100000 + 5, MaxQ = 100000 + 5; int n, m, q, Top, Tot;
int Father[MaxT], Son[MaxT][2], V[MaxT], T[MaxT], f[MaxN], Size[MaxN], Ans[MaxQ]; bool isRoot[MaxT], Rev[MaxT]; struct ES
{
int u, v, w, Idx;
bool Del;
} E[MaxM]; struct QR
{
int f, x, y, Pos;
} Q[MaxQ]; inline bool CmpW(ES e1, ES e2)
{
return e1.w < e2.w;
} inline bool CmpIdx(ES e1, ES e2)
{
return e1.Idx < e2.Idx;
} inline bool CmpUV(ES e1, ES e2)
{
return (e1.u < e2.u) || (e1.u == e2.u && e1.v < e2.v);
} int FindIdx(int x, int y)
{
if (x > y) swap(x, y);
int l, r, mid;
l = 1; r = m;
while (l <= r)
{
mid = (l + r) >> 1;
if (E[mid].u == x && E[mid].v == y) break;
if ((E[mid].u < x) || (E[mid].u == x && E[mid].v < y)) l = mid + 1;
else r = mid - 1;
}
return mid;
} inline int Find(int x)
{
int i, j, k;
j = x;
while (j != f[j]) j = f[j];
i = x;
while (i != j)
{
k = i;
i = f[i];
f[k] = j;
}
return j;
} inline void UN(int x, int y)
{
if (Size[x] == Size[y]) ++Size[x];
if (Size[x] > Size[y]) f[y] = x;
else f[x] = y;
} /********************* LCT Begin *********************/ inline int gmax(int a, int b) {return V[a] > V[b] ? a : b;} inline void Update(int x)
{
T[x] = gmax(x, gmax(T[Son[x][0]], T[Son[x][1]]));
} inline void Reverse(int x)
{
Rev[x] = !Rev[x];
swap(Son[x][0], Son[x][1]);
} inline void PushDown(int x)
{
if (!Rev[x]) return;
Rev[x] = false;
if (Son[x][0]) Reverse(Son[x][0]);
if (Son[x][1]) Reverse(Son[x][1]);
} inline int GetDir(int x)
{
if (x == Son[Father[x]][0]) return 0;
else return 1;
} void Rotate(int x)
{
int y = Father[x], f;
PushDown(y); PushDown(x);
if (x == Son[y][0]) f = 1;
else f = 0;
if (isRoot[y])
{
isRoot[y] = false;
isRoot[x] = true;
}
else
{
if (y == Son[Father[y]][0]) Son[Father[y]][0] = x;
else Son[Father[y]][1] = x;
}
Father[x] = Father[y];
Son[y][f ^ 1] = Son[x][f];
if (Son[x][f]) Father[Son[x][f]] = y;
Son[x][f] = y;
Father[y] = x;
Update(y); Update(x);
} void Splay(int x)
{
int y;
while (!isRoot[x])
{
y = Father[x];
if (isRoot[y])
{
Rotate(x);
break;
}
if (GetDir(y) == GetDir(x)) Rotate(y);
else Rotate(x);
Rotate(x);
}
} int Access(int x)
{
int y = 0;
while (x != 0)
{
Splay(x);
PushDown(x);
if (Son[x][1]) isRoot[Son[x][1]] = true;
Son[x][1] = y;
if (y) isRoot[y] = false;
Update(x);
y = x;
x = Father[x];
}
return y;
} inline void Make_Root(int x)
{
int t = Access(x);
Reverse(t);
} void Link(int x, int y)
{
Make_Root(x);
Splay(x);
Father[x] = y;
} void Cut(int x, int y)
{
Make_Root(x);
Access(y);
Splay(y);
PushDown(y);
isRoot[Son[y][0]] = true;
Father[Son[y][0]] = 0;
Son[y][0] = 0;
Update(y);
} /********************* LCT End *********************/ int main()
{
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= m; ++i)
{
Read(E[i].u); Read(E[i].v); Read(E[i].w);
if (E[i].u > E[i].v) swap(E[i].u, E[i].v);
E[i].Del = false;
}
sort(E + 1, E + m + 1, CmpW); // by ES.w
for (int i = 1; i <= m; ++i)
{
E[i].Idx = i;
V[n + i] = E[i].w;
}
for (int i = 1; i <= n + m; ++i)
{
isRoot[i] = true;
Father[i] = 0;
T[i] = i;
}
sort(E + 1, E + m + 1, CmpUV); // by ES.u && ES.v
int t;
for (int i = 1; i <= q; ++i)
{
Read(Q[i].f); Read(Q[i].x); Read(Q[i].y);
if (Q[i].f == 2)
{
t = FindIdx(Q[i].x, Q[i].y);
E[t].Del = true;
Q[i].Pos = E[t].Idx;
}
else ++Top;
}
Tot = Top;
for (int i = 1; i <= n; ++i)
{
f[i] = i;
Size[i] = 1;
}
sort(E + 1, E + m + 1, CmpIdx); // by ES.Idx
int Cnt = 0, fx, fy;
for (int i = 1; i <= m; ++i)
{
if (E[i].Del) continue;
fx = Find(E[i].u); fy = Find(E[i].v);
if (fx == fy) continue;
UN(fx, fy);
Link(E[i].u, n + i); Link(E[i].v, n + i);
if (++Cnt == n - 1) break;
}
int CutE;
for (int i = q; i >= 1; --i)
{
Make_Root(Q[i].x);
t = Access(Q[i].y);
if (Q[i].f == 1) Ans[Top--] = V[T[t]];
else
{
if (E[Q[i].Pos].w >= V[T[t]]) continue;
CutE = T[t];
Cut(CutE, E[CutE - n].u); Cut(CutE, E[CutE - n].v);
Link(Q[i].x, n + Q[i].Pos); Link(Q[i].y, n + Q[i].Pos);
}
}
for (int i = 1; i <= Tot; ++i) printf("%d\n", Ans[i]);
return 0;
}
[BZOJ 2594] [Wc2006]水管局长数据加强版 【LCT】的更多相关文章
- BZOJ 2594: [Wc2006]水管局长数据加强版 [LCT kruskal]
2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec Memory Limit: 128 MBSubmit: 2917 Solved: 918[Submit][St ...
- BZOJ 2594: [Wc2006]水管局长数据加强版( LCT )
离线然后就是维护加边的动态MST, Link cut tree秒掉..不过我写+调了好久...时间复杂度O(NlogN + MlogM) ------------------------------- ...
- BZOJ 2594: [Wc2006]水管局长数据加强版 (LCT维护最小生成树)
离线做,把删边转化为加边,那么如果加边的两个点不连通,直接连就行了.如果联通就找他们之间的瓶颈边,判断一下当前边是否更优,如果更优就cut掉瓶颈边,加上当前边. 那怎么维护瓶颈边呢?把边也看做点,向两 ...
- bzoj 2594: [Wc2006]水管局长数据加强版 动态树
2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec Memory Limit: 128 MBSubmit: 934 Solved: 291[Submit][Sta ...
- BZOJ 2594: [Wc2006]水管局长数据加强版(kruskal + LCT)
Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一 ...
- 【刷题】BZOJ 2594 [Wc2006]水管局长数据加强版
Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一 ...
- bzoj 2594: [Wc2006]水管局长数据加强版
Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一 ...
- bzoj 2594 [Wc2006]水管局长数据加强版(LCT+最小生成树)
[深坑勿入] [给个链接] http://blog.csdn.net/popoqqq/article/details/41348549 #include<cstdio> #include& ...
- [bzoj2594][Wc2006]水管局长数据加强版 (lct)
论蒟蒻的自我修养T_T.. 和noi2014魔法森林基本一样...然而数据范围大得sxbk...UPD:这题如果用lct判联通的话可能会被卡到O(mlogm)..所以最好还是用并查集吧 一开始数组开太 ...
随机推荐
- android81 多线程下载和断电续传
package com.itheima.multithreaddownload; import java.io.BufferedReader; import java.io.File; import ...
- AHCI vs NVMe
http://www.hkepc.com/13139 儘管現時有不少高階 SSD 產品改用 PCIe 接口,以突破 SATA 接口的頻寬瓶頸,但控制器設計與 SATA 接口 SSD 一樣,採用老舊的 ...
- Obj2002java
计算球体积 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submi ...
- awk实用技巧
awk '{sum+=$1} END {print "Sum = ", sum}' awk '{sum+=$1} END {print "Average = " ...
- mysql-distinct去重、mysql-group …
一.MYSQL-distinct用法 在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记 ...
- javascript 之原型理解
最近一直在了解javascript原型的问题,也算是理解了一点,希望把我所理解的,用简单的例子和说明,让更多人清除的去理解javascript原型 1,原型 prototype 是一个什么东西 我们创 ...
- TCP/IP 协议理解
TCP/IP 协议(Transmission Control Protocol / internet Protocol),因特网互联协议,又名网络通讯协议.通俗而言:TCP负责发现传输的问题,一有问题 ...
- PHP提高编程效率的方法,你知道多少呢?
PHP语言是最WEB的计算机语言,而且也是应用最广泛的语言,那么PHP对编程的影响有多大呢?下面可以去了解一下. 用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜 ...
- C#语法糖之第六篇: 泛型委托- Predicate<T>、Func<T>
今天继续分享泛型委托的Predicate<T>,上篇文章讲了Action委托,这个比Action委托功不一样的地方就是委托引用方法是Bool返回值的方法,Action为无返回值.首先我们看 ...
- Android- Context理解
学习了安卓以后还是不理解Context的用法:Api文档链接http://wear.techbrood.com/reference/android/content/Context.html 一个非常好 ...