SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了。嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项。
在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗、消毒等等。嘟嘟在控制中心一声令下,这些水管的准备操作同时开始,但由于各条管道的长度、内径不同,进行准备操作需要的时间可能不同。供水公司总是希望嘟嘟能找到这样一条送水路径,路径上的所有管道全都准备就绪所需要的时间尽量短。嘟嘟希望你能帮助他完成这样的一个选择路径的系统,以满足供水公司的要求。另外,由于MY市的水管年代久远,一些水管会不时出现故障导致不能使用,你的程序必须考虑到这一点。
不妨将MY市的水管网络看作一幅简单无向图(即没有自环或重边):水管是图中的边,水管的连接处为图中的结点。
 

Input

输入文件第一行为3个整数:N, M, Q分别表示管道连接处(结点)的数目、目前水管(无向边)的数目,以及你的程序需要处理的任务数目(包括寻找一条满足要求的路径和接受某条水管坏掉的事实)。
以下M行,每行3个整数x, y和t,描述一条对应的水管。x和y表示水管两端结点的编号,t表示准备送水所需要的时间。我们不妨为结点从1至N编号,这样所有的x和y都在范围[1, N]内。
以下Q行,每行描述一项任务。其中第一个整数为k:若k=1则后跟两个整数A和B,表示你需要为供水公司寻找一条满足要求的从A到B的水管路径;若k=2,则后跟两个整数x和y,表示直接连接x和y的水管宣布报废(保证合法,即在此之前直接连接x和y尚未报废的水管一定存在)。
 

Output

按顺序对应输入文件中每一项k=1的任务,你需要输出一个数字和一个回车/换行符。该数字表示:你寻找到的水管路径中所有管道全都完成准备工作所需要的时间(当然要求最短)。
 

Sample Input

4 4 3
1 2 2
2 3 3
3 4 2
1 4 2
1 1 4
2 1 4
1 1 4

Sample Output

2
3

【原题数据范围】
N ≤ 1000
M ≤ 100000
Q ≤ 100000
测试数据中宣布报废的水管不超过5000条;且任何时候我们考虑的水管网络都是连通的,即从任一结点A必有至少一条水管路径通往任一结点B。

 
题解:
很显然根据克鲁斯卡尔求最小生成树的思路下,对于最小生成树来说,树上任意两个点之间的非树边与原树边构成的环里,这条非树边肯定是最长的,进而可以推出最小生成树上任意两点之间的沿树边上的最大值是整张图中这两点之间最大值中最小的。
所以问题转化成了动态求最小生成树
显然删边不好做,就可以倒过来搞,故事就变成了加边
加边这个东西相当于比较新加的这条边边权和新加边连接两点的树边上最大的边哪个大。
如果原边大的话显然需要把新边加进去,也就是把旧边断开,新边连上
边权显然不好维护,可以考虑把所有边都换成点,于是就边权换点权了。
但是需要注意一点,这样子要cut两次,在cut的时候注意make_root,或者记录一下原点,因为原点会变qwq(为此调了半个上午)
 
代码如下:
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1100010
#define mp make_pair
#define lson ch[x][0]
#define rson ch[x][1]
#define pii pair<int,int>
using namespace std; struct node
{
int from,to,w;
} e[N];
struct o
{
int from,to,kd,w,ori;
} op[N];
int n,m,k;
map<pii,int> m1,m2; int cmp(node a,node b)
{
return a.w<b.w;
} //lct start int f[N],ch[N][],w[N],tag[N],sum[N]; int not_root(int now)
{
int x=f[now];
return lson==now||rson==now;
} int push_up(int x)
{
sum[x]=x;
if(e[sum[lson]].w>e[sum[x]].w)
{
sum[x]=sum[lson];
}
if(e[sum[rson]].w>e[sum[x]].w)
{
sum[x]=sum[rson];
}
} int rev(int x)
{
swap(lson,rson);
tag[x]^=;
} int push_down(int x)
{
if(tag[x])
{
rev(lson);
rev(rson);
tag[x]^=;
}
} int rotate(int x)
{
int y=f[x],z=f[y],kd=ch[y][]==x,xs=ch[x][!kd];
if(not_root(y)) ch[z][ch[z][]==y]=x;
ch[x][!kd]=y;
ch[y][kd]=xs;
if(xs) f[xs]=y;
f[x]=z;
f[y]=x;
push_up(y);
} int push_all(int x)
{
if(not_root(x))
{
push_all(f[x]);
}
push_down(x);
} int splay(int x)
{
int y,z;
push_all(x);
while(not_root(x))
{
int y=f[x],z=f[y];
if(not_root(y))
{
(ch[y][]==x)^(ch[z][]==y)?rotate(x):rotate(y);
}
rotate(x);
}
push_up(x);
} int access(int x)
{
for(int y=; x; y=x,x=f[x])
{
splay(x);
rson=y;
push_up(x);
}
} int make_root(int x)
{
access(x);
splay(x);
rev(x);
} int split(int x,int y)
{
make_root(x);
access(y);
splay(y);
} int find_root(int x)
{
access(x);
splay(x);
while(lson)
{
push_down(x);
x=lson;
}
return x;
} int link(int x,int y)
{
make_root(x);
if(find_root(y)==x) return ;
f[x]=y;
return ;
} int cut(int x,int y)
{
make_root(x);
if(find_root(y)!=x||f[x]!=y||rson) return ;
f[x]=ch[y][]=;
push_up(y);
return ;
} int print(int x)
{
if(lson) print(lson);
printf("%d ",x);
if(rson) print(rson);
} //lct end // dsu start int fa[N]; int init()
{
for(int i=; i<N; i++)
{
fa[i]=i;
}
} int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
} int unity(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx==fy) return ;
fa[x]=y;
return ;
} //dsu end int main()
{
init();
scanf("%d%d%d",&n,&m,&k);
for(int i=; i<=m; i++)
{
scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w); }
sort(e+,e+m+,cmp);
for(int i=; i<=m; i++)
{
m2[mp(e[i].from,e[i].to)]=i;
m2[mp(e[i].to,e[i].from)]=i;
}
int kd,from,to;
for(int i=; i<=k; i++)
{
scanf("%d%d%d",&op[i].kd,&op[i].from,&op[i].to);
if(op[i].kd==)
{
m1[mp(op[i].from,op[i].to)]=;
m1[mp(op[i].to,op[i].from)]=;
op[i].ori=m2[mp(op[i].from,op[i].to)];
op[i].w=e[op[i].ori].w;
}
}
for(int i=; i<=m; i++)
{
if(m1[mp(e[i].from,e[i].to)]>) continue;
if(unity(e[i].from,e[i].to))
{
link(e[i].from+m,i);
link(e[i].to+m,i);
}
}
stack<int> ans;
for(int i=k; i>=; i--)
{
if(op[i].kd==)
{
split(op[i].from+m,op[i].to+m);
ans.push(e[sum[op[i].to+m]].w);
}
if(op[i].kd==)
{
split(op[i].from+m,op[i].to+m);
if(e[sum[op[i].to+m]].w>op[i].w)
{
int gg=sum[op[i].to+m];
cut(e[sum[op[i].to+m]].from+m,gg);
cut(e[sum[op[i].to+m]].to+m,gg);
link(op[i].from+m,op[i].ori);
link(op[i].to+m,op[i].ori);
}
}
}
while(!ans.empty())
{
printf("%d\n",ans.top());
ans.pop();
}
}
 
 

洛谷P4172 [WC2006]水管局长(lct求动态最小生成树)的更多相关文章

  1. 洛谷P4172 [WC2006]水管局长 (LCT,最小生成树)

    洛谷题目传送门 思路分析 在一个图中,要求路径上最大边边权最小,就不难想到最小生成树.而题目中有删边的操作,那肯定是要动态维护啦.直接上LCT维护边权最小值(可以参考一下蒟蒻的Blog) 这时候令人头 ...

  2. 洛谷.4172.[WC2006]水管局长(LCT Kruskal)

    题目链接 洛谷(COGS上也有) 不想去做加强版了..(其实处理一下矩阵就好了) 题意: 有一张图,求一条x->y的路径,使得路径上最长边尽量短并输出它的长度.会有<=5000次删边. 这 ...

  3. [洛谷P4172] WC2006 水管局长

    问题描述 SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水 ...

  4. luogu P4172 [WC2006]水管局长 LCT维护动态MST + 离线

    Code: #include<bits/stdc++.h> #define maxn 1200000 #define N 120000 using namespace std; char ...

  5. 洛谷4172 WC2006水管局长(LCT维护最小生成树)

    这个题和魔法森林感觉有很相近的地方啊 同样也是维护一个类似最大边权最小的生成树 但是不同的是,这个题是有\(cut\)和询问,两种操作.... 这可如何是好啊? 我们不妨倒着来考虑,假设所有要\(cu ...

  6. P4172 [WC2006]水管局长 LCT维护最小生成树

    \(\color{#0066ff}{ 题目描述 }\) SC 省 MY 市有着庞大的地下水管网络,嘟嘟是 MY 市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的 ...

  7. 洛谷 4172 [WC2006]水管局长

    [题解] 我们把操作倒过来做,就变成了加边而不是删边.于是用LCT维护动态加边的最小生成树就好了.同样要注意把边权变为点权. #include<cstdio> #include<al ...

  8. 【洛谷P4172】水管局长

    题目大意:给定 N 个点,M 条边的无向图,支持两种操作:动态删边和查询任意两点之间路径上边权的最大值最小是多少. 题解: 引理:对原图求最小生成树,可以保证任意两点之间的路径上边权的最大值取得最小值 ...

  9. P4172 [WC2006]水管局长(LCT)

    P4172 [WC2006]水管局长 LCT维护最小生成树,边权化点权.类似 P2387 [NOI2014]魔法森林(LCT) 离线存储询问,倒序处理,删边改加边. #include<iostr ...

随机推荐

  1. apache 自定义404错误页面

    1.有些提供web服务的网站,在用户访问一个不存在的网站文件时,会提示404错误,如下所示: 现在要求自定义一个错误页面,也就是出现404错误代码时,跳转到我们自定义的网址上.下面记录下方法: 1.编 ...

  2. Julia - 数学运算

    算术运算符 算术运算符适用于所有的基本数值类型 +x,一元加法,就是 x 本身 -x,一元减法,x 的相反数 x + y,二元加法,做加法运算 x - y,二元减法,做减法运算 x * y,乘法,做乘 ...

  3. ubuntu用户添加adduser, useradd并给予sudo权限

    ubuntu用户添加adduser, useradd并给予sudo权限 2016-06-15 10:36 1286人阅读 评论(0) 收藏 举报  分类: Ubuntu(80)  ubuntu和win ...

  4. 【MySQL】教程及常用工具和操作

    12.MySQL菜鸟教程 http://www.runoob.com/mysql/mysql-data-types.html 3.MySQL Workbench怎么使用及其使用教程 https://j ...

  5. 分享Axure RP8.0激活码一份

    用户名:aaa 注册码:2GQrt5XHYY7SBK/4b22Gm4Dh8alaR0/0k3gEN5h7FkVPIn8oG3uphlOeytIajxGU

  6. keil5破解

    没有破解之前的keil只能编译限制大小的代码,72K好像我忘了?太长的话会报错. 注册机网址:http://bbs.armfly.com/read.php?tid=2346 1.在keil5左上角的F ...

  7. [转] c# 操作Word

    来自 风过四季天 的原文 c# 操作Word总结 在医疗管理系统中为保存患者的体检和治疗记录,方便以后的医生或其他人查看.当把数据保存到数据库中,需要新建很多的字段,而且操作很繁琐,于是想 到网页的信 ...

  8. [转]DWZ表单验证规则一览表(留着自己用)

    <form onsubmit="return validateCallback(this)" class="pageForm" action=" ...

  9. 使用火狐浏览器访问双向认证的k8s api

    首先 不能在火狐里对要访问的网址添加例外 打开 选项->高级->查看证书->证书机构->导入.先择服务端ca.crt后根据提示导入证书 生成p12文件 openssl pkcs ...

  10. Asp.net 使用Neatupload 第三方控件上传大文件,在IIS7上无法正常工作解决

    使用环境:Window Server2008 + IIS7 更改web.config配置 1.在<configSections></configSections>节内加入: & ...