传送门
(好久不打lct板子都快忘了
lct维护边权的套路就是把边拆成点,这个点向两边的点分别连边,点权就是边权,原树上的点根据需要可以设点权为inf或者-inf
动态最小生成树离线删边变加边,就是在 l c t lct lct中记录 m x [ x ] mx[x] mx[x]和 i d [ x ] id[x] id[x]表示子树点权中最大的点权和点的编号,加入一条新边 ( x , y ) (x,y) (x,y)的时候,如果两点没有联通就连起来,如果已经联通就 s p l i t ( x , y ) split(x,y) split(x,y),看最大的点权是不是比新加的点权大,大的话就把它原图中两边的点都 c u t cut cut掉然后 l i n k link link上这条边
话说第一回开大数组还 M L E MLE MLE了一次QAQ
还有第一次可以用并查集 k r u s c a l kruscal kruscal做!并查集常数比 l c t lct lct不知道优秀多少,本地(机子比较慢)最大的数据点用 l c t lct lct做跑了 13 s 13s 13s,但是换成并查集的 k r u s c a l kruscal kruscal就只跑了 4 s 4s 4s
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#define inf 0x3f3f3f3f
#define N 1100005
#define M 1000005
#define maxn 100005
#define ls ch[x][0]
#define rs ch[x][1]
#define LL long long
using namespace std;
template<class T>inline void rd(T &x){
x=0; short f=1; char c=getchar();
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+(c^'0'),c=getchar();
x*=f;
}
namespace lct{
int ch[N][2],f[N],rev[N],mx[N],id[N],w[N];
inline int get(int x){return ch[f[x]][1]==x;}
inline void update(int x){
mx[x]=w[x],id[x]=x;
if(ls || rs){
mx[x]=w[x],id[x]=x;
if(mx[x]<mx[ls]) mx[x]=mx[ls],id[x]=id[ls];
if(mx[x]<mx[rs]) mx[x]=mx[rs],id[x]=id[rs];
}
}
inline int isroot(int x){return ch[f[x]][0]!=x && ch[f[x]][1]!=x;}
inline void rever(int x){rev[x]^=1;swap(ls,rs);}
inline void pushdown(int x){
if(rev[x]){
if(ls) rever(ls);
if(rs) rever(rs);
rev[x]=0;
}
}
void pushup(int x){if(!isroot(x))pushup(f[x]);pushdown(x);}
inline void rotate(int x){
int wh=get(x),old=f[x],oldf=f[old];
if(!isroot(old)) ch[oldf][get(old)]=x;
ch[old][wh]=ch[x][wh^1],f[ch[x][wh^1]]=old;
f[old]=x,ch[x][wh^1]=old,f[x]=oldf;
update(old); update(x);
}
inline void splay(int x){
pushup(x);
for(;!isroot(x);rotate(x))
if(!isroot(f[x])) rotate(get(f[x])==get(x)?f[x]:x);
}
inline void access(int x){
for(int y=0;x;y=x,x=f[x]) splay(x),rs=y,update(x);
}
inline void makeroot(int x){
access(x); splay(x); rever(x);
}
inline int findroot(int x){
access(x); splay(x);
while(ls) pushdown(x),x=ls; return x;
}
inline void split(int x,int y){
makeroot(x); access(y); splay(y);
}
inline void link(int x,int y){
makeroot(x); f[x]=y;
}
inline void cut(int x,int y){
split(x,y);
if(ch[y][0]==x && ch[x][1]==0)
f[x]=ch[y][0]=0,update(y);
}
}
int n,m,Q,q[maxn][3],tot,fr2[M],to2[M],ans[maxn],val[maxn],fa[maxn];
map<pair<int,int>,int> mp;
inline int find(int x){
return x==fa[x]?x:(fa[x]=find(fa[x]));
}
struct EDGE{
int fr,to,w;
bool operator <(const EDGE &x) const{
return w<x.w;
}
}edge[M];
int main(){
rd(n); rd(m); rd(Q);
for(int i=1;i<=m;i++){
rd(edge[i].fr); rd(edge[i].to); rd(edge[i].w);
}
for(int i=1;i<=Q;i++){
rd(q[i][0]); rd(q[i][1]); rd(q[i][2]);
if(q[i][0]==2)
mp[make_pair(q[i][1],q[i][2])]=mp[make_pair(q[i][2],q[i][1])]=i;
}
tot=n;
for(int i=1;i<=n;i++) lct::w[i]=-inf,fa[i]=i;
sort(edge+1,edge+m+1);
for(int i=1;i<=m;i++)
if(!mp.count(make_pair(edge[i].fr,edge[i].to))){
int x=edge[i].fr,y=edge[i].to;
int u=find(x),v=find(y);
if(u!=v){
lct::w[++tot]=edge[i].w; fr2[tot]=x,to2[tot]=y;
lct::link(x,tot),lct::link(y,tot); fa[u]=v;
}
// else{
// lct::split(x,y);
// if(lct::mx[y]>w[i]){
// int now=lct::id[y];
// lct::cut(fr2[now],now),lct::cut(to2[now],now);
// lct::w[++tot]=w[i]; fr2[tot]=x,to2[tot]=y;
// lct::link(x,tot),lct::link(y,tot);
// }
// }
}
else val[mp[make_pair(edge[i].fr,edge[i].to)]]=edge[i].w;
for(int i=Q;i;i--){
if(q[i][0]==1){
int x=q[i][1],y=q[i][2];
lct::split(x,y);
ans[i]=lct::mx[y];
}
else{
int x=q[i][1],y=q[i][2],z=val[i];
if(lct::findroot(x)!=lct::findroot(y)){
lct::w[++tot]=z; fr2[tot]=x,to2[tot]=y;
lct::link(x,tot),lct::link(y,tot);
}
else{
lct::split(x,y);
if(lct::mx[y]>z){
int now=lct::id[y];
lct::cut(fr2[now],now),lct::cut(to2[now],now);
lct::w[++tot]=z; fr2[tot]=x,to2[tot]=y;
lct::link(x,tot),lct::link(y,tot);
}
}
}
}
for(int i=1;i<=Q;i++)
if(q[i][0]==1) printf("%d\n",ans[i]);
return 0;
}