来自FallDream的博客,未经允许,请勿转载,谢谢。
简要题意:给定一张n个点m条边的图,有边权,需要支持两个操作 1)删除一条边2)求两点之间边权最大值的最小值 n和操作次数不超过10^5,m<=10^6
题解:很显然要你维护的是一个最小生成树qaq
然后删边太难了,考虑倒过来加边,用边权lct维护最小生成树。每个点维护向父亲和偏爱儿子的连边的编号,还有他所在的splay的最左边和最右边的那条边(不懂边权lct可以自行百度)
假设你要插入边u->v,如果它们不连通,直接插入。不然的话,如果u->v的路径上的边权的最大值超过了这条边的边权,删掉最大的那条边,加入这条边就行了。
lct常数巨大 所以一开始把没被删除的边插入的时候不能lct,要用kruscal,不然T的飞起。
#include<iostream> #include<cstdio> #include<algorithm> #define MN 100000 #define INF 2000000000 #define getchar() (*S++) using namespace std; char B[1<<26],*S=B; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,Q,rk[MN*10+5],fa[MN+5],qu[MN+5],top,c[MN+5][2],mx[MN+5],s[MN+5],p[MN+5],f[MN+5],L[MN+5],R[MN+5],ans[MN+5]; bool rev[MN+5],mark[MN*10+5]; struct edge{int from,to,w,num; bool operator<(const edge&b)const{return from==b.from?to<b.to:from<b.from;} }e[MN*10+5]; struct ques{int kind,x,y;}q[MN+5]; inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} inline void pushdown(int x) { if(rev[x]) { int l=c[x][0],r=c[x][1]; rev[l]^=1;rev[r]^=1;rev[x]^=1; swap(c[x][0],c[x][1]); swap(L[l],R[l]);swap(f[l],p[l]); swap(L[r],R[r]);swap(f[r],p[r]); } } inline void U(int&x,int y){if(e[x].w<e[y].w) x=y;} inline void update(int x) { mx[x]=(e[f[x]].w>e[p[x]].w)?f[x]:p[x]; L[x]=f[x];R[x]=p[x]; int l=c[x][0],r=c[x][1]; if(l) L[x]=L[l],U(mx[x],mx[l]),U(mx[x],p[l]); if(r) R[x]=R[r],U(mx[x],mx[r]),U(mx[x],f[r]); } void rotate(int x) { int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; if(!isroot(y)) c[z][c[z][1]==y]=x; fa[x]=z;fa[y]=x;fa[c[x][r]]=y; c[y][l]=c[x][r];c[x][r]=y; update(y);update(x); } void splay(int x) { qu[top=1]=x; for(int t=x;!isroot(t);t=fa[t]) qu[++top]=fa[t]; for(;top;--top) pushdown(qu[top]); for(;!isroot(x);rotate(x)) if(!isroot(fa[x])) rotate((c[fa[fa[x]]][1]==fa[x]^c[fa[x]][1]==x)?x:fa[x]); } void access(int x) { for(int y=0;x;x=fa[y=x]) splay(x),c[x][1]=y,p[x]=L[y],update(x); } void link(int x,int y,int z) { access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]); access(y);fa[c[y][1]=x]=y;f[x]=p[y]=z; update(x);update(y); } void cut(int x,int y) { access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]); access(y);splay(y);c[y][0]=fa[x]=f[y]=p[x]=0; update(x);update(y); } void ins(int id) { int x=e[id].from,y=e[id].to,z=e[id].w; access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]); access(y);splay(y); if(isroot(x)) link(x,y,id); else if(e[mx[y]].w>z) cut(e[mx[y]].from,e[mx[y]].to),link(x,y,id); } inline int getfa(int x){return !s[x]?x:s[x]=getfa(s[x]);} bool cmp(int x,int y){return e[x].w<e[y].w;} int main() { fread(B,1,1<<26,stdin); e[0].w=-INF; n=read();m=read();Q=read(); for(register int i=1;i<=m;i++) { e[i].from=read(),e[i].to=read(),e[i].w=read(); if(e[i].from>e[i].to) swap(e[i].from,e[i].to); } sort(e+1,e+m+1); for(int i=1;i<=m;i++) rk[i]=i; for(register int i=1;i<=Q;i++) { q[i].kind=read();q[i].x=read();q[i].y=read(); if(q[i].kind==2) { if(q[i].x>q[i].y) swap(q[i].x,q[i].y); q[i].x=lower_bound(e+1,e+m+1,(edge){q[i].x,q[i].y,0})-e; mark[q[i].x]=1; } } sort(rk+1,rk+m+1,cmp); for(register int i=1;i<=m;i++) if(!mark[rk[i]]) { int x=getfa(e[rk[i]].from),y=getfa(e[rk[i]].to); if(x!=y) s[x]=y,link(e[rk[i]].from,e[rk[i]].to,rk[i]); } for(register int i=Q;i;i--) if(q[i].kind==2) ins(q[i].x); else { int x=q[i].x,y=q[i].y; access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]); access(y);splay(y); ans[i]=e[mx[y]].w; } for(register int i=1;i<=Q;i++) if(q[i].kind<2) printf("%d ",ans[i]); return 0; }