差值最小生成樹[LCT]
阿新 • • 發佈:2018-11-04
將邊按邊權從小到大排序;
如果插入的兩個點在一棵樹上,就找他們路徑上權值最小的那條邊並刪除,然後在新加一條邊
否則直接加就好了
路徑需要以點的形式插入到LCT,第i跳路徑對於i+n號節點,Link(x,y) 就Link(x,i+n),Link(i+n,y) 就好了
維護一下最小值
#include<bits/stdc++.h> #define N 1000005 #define lc t[x].ch[0] #define rc t[x].ch[1] using namespace std; struct Node{ int ch[2],Min,fa,tag; }t[N]; struct Edge{int x,y,val;}E[N]; bool cmp(Edge a,Edge b){return a.val<b.val;} int n,m,ans=1e9,mi,cnt,vis[N],val[N]; int read(){ int cnt=0,f=1;char ch=0; while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar(); return cnt*f; } bool isRoot(int x){ int fa=t[x].fa; return t[fa].ch[0]!=x && t[fa].ch[1]!=x; } void Pushup(int x){ t[x].Min=x; if(lc && val[t[lc].Min] < val[t[x].Min]) t[x].Min = t[lc].Min; if(rc && val[t[rc].Min] < val[t[x].Min]) t[x].Min = t[rc].Min; } void Pushdown(int x){ if(t[x].tag){ swap(lc,rc); t[lc].tag^=1; t[rc].tag^=1; t[x].tag=0; } } void Pushpath(int x){ if(!isRoot(x)) Pushpath(t[x].fa); Pushdown(x); } void rotate(int x){ int y=t[x].fa,z=t[y].fa; int k=t[y].ch[1]==x; if(!isRoot(y)) t[z].ch[t[z].ch[1]==y]=x; t[x].fa=z; t[y].ch[k]=t[x].ch[k^1]; t[t[x].ch[k^1]].fa=y; t[x].ch[k^1]=y,t[y].fa=x; Pushup(y),Pushup(x); } void Splay(int x){ Pushpath(x); while(!isRoot(x)){ int y=t[x].fa,z=t[y].fa; if(!isRoot(y)) (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y); rotate(x); } } void Access(int x){ for(int y=0;x;y=x,x=t[x].fa) Splay(x),rc=y,Pushup(x); } int Findroot(int x){ Access(x),Splay(x); while(lc) Pushdown(x),x=lc; return x; } void Makeroot(int x){ Access(x),Splay(x),t[x].tag^=1; } void Link(int x,int y){ Makeroot(x),t[x].fa=y; } void Cut(int x,int y){ Makeroot(x),Access(y),Splay(y); t[y].ch[0]=0,t[x].fa=0,Pushup(y); } int Split(int x,int y){ Makeroot(x),Access(y),Splay(y); return t[y].Min; } int main(){ n=read(),m=read(); for(int i=1;i<=m;i++){ E[i].x=read() , E[i].y=read() , E[i].val=read(); if(E[i].x==E[i].y) i--,m--; } sort(E+1,E+m+1,cmp); for(int i=0;i<=n;i++) val[i]=1e9; for(int i=1;i<=m;i++) val[i+n]=E[i].val; for(int i=1;i<=m;i++){ int x=E[i].x,y=E[i].y; if(Findroot(x)==Findroot(y)){ int tmp=Split(x,y); Cut(E[tmp-n].x,tmp),Cut(tmp,E[tmp-n].y); vis[tmp-n]=0; Link(x,i+n),Link(i+n,y); vis[i]=1; while(!vis[mi]) mi++; } else{ cnt++,vis[i]=1; Link(x,i+n),Link(i+n,y); } if(cnt==n-1) ans=min(ans,E[i].val-E[mi].val); }printf("%d\n",ans); return 0; }