☆ [WC2006] 水管局长 「LCT动态维护最小生成树」
题目类型:\(LCT\)动态维护最小生成树
传送门:>Here<
题意:给出一张简单无向图,要求找到两点间的一条路径,使其最长边最小。同时有删边操作
解题思路
两点间路径的最长边最小,也就是等同于要求最小生成树。因此如果没有删边操作,那么只要\(Kruscal\)一遍就好了。
然而现在需要删边,也就是意味着最小生成树需要不停地重构……那怎么维护呢?
考虑离线,倒着处理所有的删边。于是乎就成为了一条一条加边。这就是标准的\(LCT\)动态维护最小生成树了。具体方法就是:如果两个点不在同一颗树中,那么\(link\)(注意,我们可以用\(findroot\)操作直接充当并查集的作用,常数稍大);否则一定出现环,查询原本环中的最大边,如果大于当前边,那么\(cut\)那条边,\(link\)这条边。
因此,我们刚开始用所有不会被删去的边维护一个最小生成树(注意要用\(kruscal\),不要动态维护,会被卡),然后再动态维护即可。
细节还是非常多的……
\(LCT\)维护点权最大值,如何来维护生成树呢?考虑将每条边变为一个点,也就是建立虚拟点,编号为\(i\)的边即为\(N+i\)。令虚拟点的权值为这条边的权值,原本的节点的权值为0,这样在查询路径上点权的最大值就好了。
如何确定被删除的边对应的权值是多少?一种思路是用邻接矩阵,要么就是用\(map\)
如果我们仅仅就是查找最大值,那么如何将其\(cut\)呢?显然我们不应该存值,而是应该存最大值的节点编号。
细节太恐怖了,调试了一晚上+一早上,结果发现是在判边的时候忘记用\(q[i]\)了……
反思
当在线无法处理的时候,可以考虑离线,将问题转化为已知的可解决的问题。
Code
/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
#define int long long
const int MAXN = 200010;
const int MAXM = 200010;
const int MAXS = MAXN+MAXM;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = 0; int w = 1; register char c = getchar();
for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
if(c == '-') w = -1, c = getchar();
for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
struct Edge{
int u,v,w;
}e[MAXM];
int N,M,Q,top;
int X[MAXM],Y[MAXM],K[MAXM],val[MAXN],ans[MAXM],idmax[MAXS],q[MAXN];
bool used[MAXM];
map <pair<int,int>, int> E;
struct LinkCutTree{
int fa[MAXS],ch[MAXS][2];
bool tag[MAXS];
inline bool rson(int f, int x){
return ch[f][1] == x;
}
inline bool isroot(int x){
return ch[fa[x]][rson(fa[x],x)] != x;
}
inline void pushup(int x){
idmax[x] = x;
if(val[idmax[ch[x][0]]] > val[idmax[x]]) idmax[x] = idmax[ch[x][0]];
if(val[idmax[ch[x][1]]] > val[idmax[x]]) idmax[x] = idmax[ch[x][1]];
}
inline void rotate(int x){
if(!x || !fa[x]) return;
int f = fa[x], gf = fa[f];
int p = rson(f, x), q = !p;
if(!isroot(f)) ch[gf][rson(gf,f)] = x; fa[x] = gf;
ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
ch[x][q] = f, fa[f] = x;
pushup(f), pushup(x);
}
inline void reverse(int x){
if(!isroot(x)) reverse(fa[x]);
if(!tag[x]) return;
tag[x] = 0;
swap(ch[x][0], ch[x][1]);
if(ch[x][0]) tag[ch[x][0]] ^= 1;
if(ch[x][1]) tag[ch[x][1]] ^= 1;
}
inline void splay(int x){
reverse(x);
while(!isroot(x)){
if(isroot(fa[x])){
rotate(x); break;
}
if(rson(fa[fa[x]],fa[x]) ^ rson(fa[x],x)) rotate(x); else rotate(fa[x]);
rotate(x);
}
}
inline void access(int x){
for(int y = 0; x; y = x, x = fa[x]){
splay(x);
ch[x][1] = y;
pushup(x);
}
}
inline void mroot(int x){
access(x);
splay(x);
tag[x] ^= 1;
}
inline int findroot(int x){
access(x);
splay(x);
while(ch[x][0]) x = ch[x][0];
return x;
}
inline void split(int x, int y){
mroot(x);
access(y);
splay(y);
}
inline void link(int x, int y){
if(findroot(x) == findroot(y)) return;
mroot(x);
fa[x] = y;
}
inline void cut(int x, int y){
split(x, y);
ch[y][0] = fa[x] = 0;
pushup(y);
}
}qxz;
inline bool cmp(const Edge& a, const Edge& b){
return a.w < b.w;
}
signed main(){
N = read(), M = read(), Q = read();
for(int i = 1; i <= M; ++i){
e[i].u = read(), e[i].v = read(), e[i].w = read();
if(e[i].u > e[i].v) swap(e[i].u, e[i].v);
}
sort(e+1, e+M+1, cmp);
for(int i = 1; i <= M; ++i){
val[N+i] = e[i].w;
E[make_pair(e[i].u,e[i].v)] = i;
}
for(int i = 1; i <= Q; ++i){
K[i] = read(), X[i] = read(), Y[i] = read() ;
if(X[i] > Y[i]) swap(X[i], Y[i]);
if(K[i] == 2){
q[i] = E[make_pair(X[i],Y[i])];
used[q[i]] = 1;
}
}
int x,y,cnt(0);
for(int i = 1; i <= M && cnt < N-1; ++i){
if(!used[i]){
x = e[i].u, y = e[i].v;
if(qxz.findroot(x) != qxz.findroot(y)){
qxz.link(x, N+i);
qxz.link(y, N+i);
++cnt;
}
}
}
for(int i = Q; i; --i){
x = X[i], y = Y[i];
if(K[i] == 2){
qxz.split(x, y);
if(val[idmax[y]] > e[q[i]].w){
int temp = idmax[y],t1 = e[temp-N].u, t2 = e[temp-N].v;
qxz.cut(t1, temp), qxz.cut(t2, temp);
qxz.link(x, N+q[i]), qxz.link(y, N+q[i]);
}
}
else{
qxz.split(x, y);
ans[++top] = val[idmax[y]];
}
}
while(top) printf("%lld\n", ans[top--]);
return 0;
}
☆ [WC2006] 水管局长 「LCT动态维护最小生成树」的更多相关文章
- ☆ [NOI2014] 魔法森林 「LCT动态维护最小生成树」
题目类型:\(LCT\)动态维护最小生成树 传送门:>Here< 题意:带权无向图,每条边有权值\(a[i],b[i]\).要求一条从\(1\)到\(N\)的路径,使得这条路径上的\(Ma ...
- [BZOJ2594] [WC2006]水管局长(Kruskal+LCT)
[BZOJ2594] [WC2006]水管局长(Kruskal+LCT) 题面 SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可 ...
- P4172 [WC2006]水管局长(LCT)
P4172 [WC2006]水管局长 LCT维护最小生成树,边权化点权.类似 P2387 [NOI2014]魔法森林(LCT) 离线存储询问,倒序处理,删边改加边. #include<iostr ...
- bzoj 2594: [Wc2006]水管局长数据加强版 动态树
2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec Memory Limit: 128 MBSubmit: 934 Solved: 291[Submit][Sta ...
- [WC2006]水管局长(LCT)
题目大意: 给定一张图,支持删边,求两点的路径中所有权值的最大值的最小值,貌似很绕的样子 由于有删边,不难想到\(LCT\),又因为\(LCT\)不支持维护图,而且只有删边操作,于是我们考虑时间回溯. ...
- 【洛谷4172】 [WC2006]水管局长(LCT)
传送门 洛谷 BZOJ Solution 如果不需要动态的话,那就是一个裸的最小生成树上的最大边权对吧. 现在动态了的话,把这个过程反着来,就是加边对吧. 现在问题变成了怎么动态维护加边的最小生成树, ...
- [BZOJ2594][WC2006]水管局长加强版(LCT+Kruskal)
2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec Memory Limit: 128 MBSubmit: 4452 Solved: 1385[Submit][S ...
- 洛谷P4172 [WC2006]水管局长(lct求动态最小生成树)
SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径, ...
- 洛谷P4172 [WC2006]水管局长 (LCT,最小生成树)
洛谷题目传送门 思路分析 在一个图中,要求路径上最大边边权最小,就不难想到最小生成树.而题目中有删边的操作,那肯定是要动态维护啦.直接上LCT维护边权最小值(可以参考一下蒟蒻的Blog) 这时候令人头 ...
随机推荐
- dsu on tree入门
先瞎扯几句 说起来我跟这个算法好像还有很深的渊源呢qwq.当时在学业水平考试的考场上,题目都做完了不会做,于是开始xjb出题.突然我想到这么一个题 看起来好像很可做的样子,然而直到考试完我都只想出来一 ...
- spring注解的相关配置
一.<context:annotation-config> 和 <context:component-scan> <context:annotation-config&g ...
- 谷歌AI涉足艺术、太空、外科手术,再强调AI七原则
谷歌AI涉足艺术.太空.外科手术,再强调AI七原则 https://mp.weixin.qq.com/s/MJG_SvKCEBKRvL3IWpL0bA 9月18日上午,Google在上海的2018世界 ...
- 林业有害生物监测系统(重庆宇创GIS)
本文由重庆宇创GIS团队原创,转载请注明来源http://www.cnblogs.com/ycdigit/p/8916073.html 一.概述 林业有害生物监测信息平台(森林病虫害监测预警系统) ...
- LEDAPS1.3.0版本移植到windows平台----HuPm参数初始化模块
这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. LEDAPS的调用顺序是:HuPm--&g ...
- 测者的测试技术手册:自动化单元工具EvoSuie的代码覆盖报告
EvoSuite是由Sheffield等大学联合开发的一种开源工具,用于自动生成测试用例集,生成的测试用例均符合Junit的标准,可直接在Junit中运行.得到了Google和Yourkit的支持. ...
- 【原】Java学习笔记023 - 字符串缓冲区_正则表达式
package cn.temptation; import java.util.Arrays; public class Sample01 { public static void main(Stri ...
- Ubuntu系统分配存储空间的建议以及给Ubuntu系统根目录扩容方法(从20GB追加100GB)
当初准备装双系统时,也思考了很久分配多少空间给Ubuntu16.04系统,查了许多资料,大多意思是‘/’目录总共给20GB,其他的给/home.网上资料推荐的大多跟这篇文章一样:https://blo ...
- docker容器日志收集方案汇总评价总结
docker日志收集方案有太多,下面截图罗列docker官方给的日志收集方案(详细请转docker官方文档).很多方案都不适合我们下面的系列文章没有说. 经过以下5篇博客的叙述简单说下docker容器 ...
- Netty初体验
package netty_starter; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFut ...