Solution
查询一条最大边权最小的路径,且要支持删边,我们可以想到用(LCT)维护最小生成树,查询(x,y)时就(split(x,y)),然后输出这条链上最大的边权即可。
维护边权我们可以将每条边都看作一个新的点(x),从原边的(2)个端点向(x)连边,将(x)的点权置为原边权,这样我们就只需要维护链上的最大点权,这就很好做了。
但是删边对最小生成树的影响让我们觉得有些棘手,考虑离线下来倒着处理,改删边为加边,注意到每加入一条边(()(u,v,w))就会导致最小生成树上出现一个环,根据最小生成树的基本性质,我们此时只要删掉换上的边权最大的边就能得到新的最小生成树。
于是我们直接查询最小生成树上(u,v)链上的最大值,将它与(w)比大小,如果(w)更大,直接跳过,否则将边权最大的那条边(cut)掉并(link)新边即可。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,mx[N],val[N],pos[N],ch[N][2],fa[N],rev[N];
inline bool which(int x){return ch[fa[x]][1]==x;}
inline void pushup(int x){
mx[x]=val[x];pos[x]=x;
if(mx[ch[x][0]]>mx[x]) mx[x]=mx[ch[x][0]],pos[x]=pos[ch[x][0]];
if(mx[ch[x][1]]>mx[x]) mx[x]=mx[ch[x][1]],pos[x]=pos[ch[x][1]];
}
inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline void rever(int x){
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
inline void pushdown(int x){
if(!rev[x]) return ;
if(ch[x][0]) rever(ch[x][0]);
if(ch[x][1]) rever(ch[x][1]);
rev[x]=0;
}
inline void Rotate(int x){
int y=fa[x],z=fa[y],wx=which(x),wy=which(y);
if(!isroot(y)) ch[z][wy]=x;fa[x]=z;
ch[y][wx]=ch[x][wx^1];
if(ch[y][wx]) fa[ch[y][wx]]=y;
ch[x][wx^1]=y;fa[y]=x;
pushup(y);
}
int stk[N],top;
inline void Splay(int x){
int now=x;
stk[top=1]=now;
while(!isroot(now)) now=fa[now],stk[++top]=now;
while(top) pushdown(stk[top--]);
while(!isroot(x)){
int y=fa[x];
if(!isroot(y)){
if(which(x)==which(y)) Rotate(y);
else Rotate(x);
}Rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int last=0;x;last=x,x=fa[x])
Splay(x),ch[x][1]=last,pushup(x);
}
inline void makeroot(int x){
access(x);Splay(x);
rever(x);
}
inline int findroot(int x){
access(x);Splay(x);
while(ch[x][0]) pushdown(x),x=ch[x][0];
Splay(x);
return x;
}
inline void split(int x,int y){
makeroot(x);access(y);
Splay(y);
}
inline void link(int x,int y){
makeroot(x);
fa[x]=y;
}
inline void cut(int x,int y){
split(x,y);
fa[x]=ch[y][0]=0;
pushup(y);
}
struct node{
int u,v,w;
}e[N],p[N];
int m,q,cnt,sum,op[N],x[N],y[N],pd[1010][1010],g[1010][1010],pa[N],ans[N];
pair<int,int> wh[N];
struct cmp{
inline bool operator ()(node x,node y){return x.w<y.w;}
};
inline int find(int x){return pa[x]==x?x:pa[x]=find(pa[x]);}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;++i){
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
if(e[i].u>e[i].v) swap(e[i].u,e[i].v);
g[e[i].u][e[i].v]=e[i].w;
}
for(int i=1;i<=q;++i){
scanf("%d%d%d",&op[i],&x[i],&y[i]);
if(op[i]==1) continue;
if(x[i]>y[i]) swap(x[i],y[i]);
if(g[x[i]][y[i]]>0) pd[x[i]][y[i]]=1;
}
for(int i=1;i<=m;++i){
if(pd[e[i].u][e[i].v]) continue;
p[++cnt]=e[i];
}
sort(p+1,p+cnt+1,cmp());
sum=n;
for(int i=1;i<=n;++i) pa[i]=i;
int tot=0;
for(int i=1;i<=cnt;++i){
int fx=find(p[i].u),fy=find(p[i].v);
if(fx==fy) continue;
pa[fx]=fy;++tot;
++sum;val[sum]=p[i].w;
wh[sum]=make_pair(p[i].u,p[i].v);
link(p[i].u,sum);link(p[i].v,sum);
if(tot==n-1) break;
}
for(int i=q;i>=1;--i){
if(op[i]==1){
split(x[i],y[i]);
ans[i]=mx[y[i]];
}
else{
int t=g[x[i]][y[i]];
split(x[i],y[i]);
if(mx[y[i]]<t) continue;
int p=pos[y[i]];
cut(wh[p].first,p);
cut(wh[p].second,p);
++sum;val[sum]=t;wh[sum]=make_pair(x[i],y[i]);
link(x[i],sum);link(y[i],sum);
}
}
for(int i=1;i<=q;++i)
if(op[i]==1)
printf("%d
",ans[i]);
return 0;
}