P4172 [WC2006] 水管局长
P4172 [WC2006] 水管局长
题目背景
SC 省 MY 市有着庞大的地下水管网络,嘟嘟是 MY 市的水管局长(就是管水管的啦)。
题目描述
每天供水公司可能要将一定量的水从
在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗、消毒等等。嘟嘟在控制中心一声令下,这些水管的准备操作同时开始,但由于各条管道的长度、内径不同,进行准备操作需要的时间可能不同。
供水公司总是希望嘟嘟能找到这样一条送水路径,路径上的所有管道全都准备就绪所需要的时间尽量短。嘟嘟希望你能帮助他完成这样的一个选择路径的系统,以满足供水公司的要求。另外,由于 MY 市的水管年代久远,一些水管会不时出现故障导致不能使用,你的程序必须考虑到这一点。
不妨将 MY 市的水管网络看作一幅简单无向图(即没有自环或重边):水管是图中的边,水管的连接处为图中的结点。整张图共有
输入格式
第一行有三个整数,分别表示管道连接处(结点)的数目
以下
以下
- 若
,则表示你需要为供水公司寻找一条满足要求的从 到 的水管路径,满足准备时间最短; - 若
,则表示直接连接 和 的水管宣布报废。
数据规模与约定
对于全部的测试点,保证:
, 。 , , 。- 给出的图无重边无自环,保证在宣布一条水管报废之前,该水管一定存在于图上且没有报废,
- 宣布报废的水管不超过
条,且在任意时刻,图一定是联通的。
Solution:
我们发现这颗树只卡特不林克,所有我们考虑将时间倒转,记录每个边被卡特的时间
然后我们发现我们其实要维护的就是 (u,v) 这条路径上所有边的最大权值并将其最小化。我们参考之前 :LCT 维护最小生成树的做法。在每个时间点
然后这题就做完了。
Code:
#include<bits/stdc++.h> const int N=3e5+5; const int inf=1e9; using namespace std; inline int Max(int x,int y){return x>y ? x : y;} int val[N]; struct LCT{ struct Tree{ int tag,ff,ch[2],mx,pos; }t[N<<2]; int st[N]; #define ls t[x].ch[0] #define rs t[x].ch[1] #define fa t[x].ff inline bool isroot(int x) { return (t[fa].ch[0]==x||t[fa].ch[1]==x); } inline void pushup(int x) { t[x].mx=val[x];t[x].pos=x; if(ls&&t[ls].mx > t[x].mx) t[x].mx=t[ls].mx,t[x].pos=t[ls].pos; if(rs&&t[rs].mx > t[x].mx) t[x].mx=t[rs].mx,t[x].pos=t[rs].pos; return; } inline void rev(int x) { swap(t[x].ch[0],t[x].ch[1]); t[x].tag^=1; return ; } inline void pushdown(int x) { if(t[x].tag) { if(ls)rev(ls); if(rs)rev(rs); t[x].tag=0; } return ; } inline void rotate(int x) { int y=fa,z=t[fa].ff,k=t[fa].ch[1]==x ? 1 : 0; if(isroot(y))t[z].ch[t[z].ch[1]==y]=x; t[x].ff=z; t[y].ch[k]=t[x].ch[!k]; if(t[x].ch[!k])t[t[x].ch[!k]].ff=y; t[x].ch[!k]=y; t[y].ff=x; pushup(y); } inline void splay(int x) { int y=x,z=0; st[++st[0]]=y; while(isroot(y))st[++st[0]]=y=t[y].ff; while(st[0])pushdown(st[st[0]--]); while(isroot(x)) { y=fa,z=t[fa].ff; if(isroot(y)){rotate((t[y].ch[1]==x)==(t[z].ch[1]==y) ? y : x);} rotate(x); } pushup(x); } void access(int x) { int y=0; while(x) { splay(x);rs=y;pushup(x); y=x;x=fa; } } void make_root(int x) { access(x);splay(x); rev(x); } int find(int x) { access(x);splay(x); while(ls)pushdown(x),x=ls; splay(x); return x; } void splite(int x,int y) { make_root(x); access(y);splay(y); } void link(int x,int y) { make_root(x); if(find(y)!=x)t[x].ff=y; return ; } void cut(int x) // 这里是减去一个点 x { splay(x); t[ls].ff=t[rs].ff=0; return ; } bool check(int x,int y) { make_root(x); return find(y)==x; } }T; struct Edge{ int u,v,w,tim; bool operator <(const Edge &e)const{ return tim<e.tim; } }e[N]; struct task{ int opt,x,y; }t[N]; #define mp(x,y) make_pair(x,y) map<pair<int,int>,int> id; int n,m,q; int ans[N]; void build(int tim) { int x,y,w,tmp,pos,mx; while(e[m].tim>=tim&&m) { x=e[m].u,y=e[m].v,w=e[m].w,val[tmp=m+n]=w; if(!T.check(x,y)) { T.link(x,tmp),T.link(tmp,y); } else { T.splite(x,y);pos=T.t[y].pos;mx=T.t[y].mx; if(w>=mx); else { T.cut(pos); T.link(x,tmp); T.link(tmp,y); } } m--; } } void work() { cin>>n>>m>>q; for(int i=1,u,v,w;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); e[i]={u,v,w,inf}; id[mp(u,v)]=id[mp(v,u)]=i; } for(int i=1,j;i<=q;i++) { scanf("%d%d%d",&t[i].opt,&t[i].x,&t[i].y); if(t[i].opt==2) { e[id[mp(t[i].x,t[i].y)]].tim=i; } } sort(e+1,e+1+m); for(int i=q,opt,x,y;i;i--) { opt=t[i].opt,x=t[i].x,y=t[i].y; if(opt==1) { build(i); T.splite(x,y); ans[i]=T.t[y].mx; } else ans[i]=-1; } for(int i=1;i<=q;i++) { if(~ans[i]) printf("%d\n",ans[i]); } } int main() { //freopen("tube.in","r",stdin);freopen("tube.out","w",stdout); work(); return 0; }