洛谷4234最小方差生成樹——LCT維護圖上資訊的應用
阿新 • • 發佈:2018-12-08
題目:luogu4234.
題目大意:給定一張無向圖,求這張無向圖最大邊和最小邊的最小權值差.
首先,我們明確一點,一棵最小生成樹上的最大邊一定最小,這一點很容易用kruskal的演算法流程來證明.
那麼我們就可以考慮一個暴力演算法,列舉一棵生成樹的最小邊,然後依照kruskal演算法加入剩下的邊來組成生成樹,取最優即可.時間複雜度.
考慮如何優化這個演算法,我們發現列舉的過程不太可能去掉,並查集的時間複雜度去掉沒有多大意義,所以我們選擇優化每一棵生成樹的生成過程.
我們考慮,當我們列舉到一條邊時,若我們當前維護的邊集中加入這條邊不會形成環,我們就將這條邊加入.否則我們找到一條形成的環上邊權最小的邊,然後刪掉這條邊加入當前的邊.當我們維護的邊集組成一棵生成樹的時候,我們就可以更新答案.
那麼我們考慮一棵LCT來維護這道題的這棵帶刪除和查詢鏈上最小值的並查集即可.
至於維護邊權的LCT,拆點維護即可.
程式碼如下:
#include<bits/stdc++.h> using namespace std; #define Abigail inline void const int N=50000,M=200000,INF=1<<29; struct tree{ int x,min,g,fa,s[2],rev; }tr[N+M+9]; int tmp[N+M+9],ttmp; int n,m,ans=INF,use[M+9]; struct side{ int x,y,v; bool operator < (const side &p)const{return v<p.v;} }e[M+9]; bool Isroot(int x){return tr[tr[x].fa].s[0]^x&&tr[tr[x].fa].s[1]^x;} void Pushup(int x){ int ls=tr[x].s[0],rs=tr[x].s[1]; if (tr[ls].min<tr[rs].min&&tr[ls].min<tr[x].x) tr[x].min=tr[ls].min,tr[x].g=tr[ls].g; else if (tr[rs].min<tr[x].x) tr[x].min=tr[rs].min,tr[x].g=tr[rs].g; else tr[x].min=tr[x].x,tr[x].g=x; } void Update_rev(int x){tr[x].rev^=1;swap(tr[x].s[0],tr[x].s[1]);} void Pushdown(int x){ if (!tr[x].rev) return; tr[x].rev=0; Update_rev(tr[x].s[0]);Update_rev(tr[x].s[1]); } void Rotate(int x){ int y=tr[x].fa,z=tr[y].fa,k=tr[y].s[1]==x; if (!Isroot(y)) tr[z].s[tr[z].s[1]==y]=x;tr[x].fa=z; tr[y].s[k]=tr[x].s[k^1];if (tr[x].s[k^1]) tr[tr[x].s[k^1]].fa=y; tr[x].s[k^1]=y;tr[y].fa=x; Pushup(y);Pushup(x); } void Splay(int x){ int y,z; tmp[ttmp=1]=x; for (int i=x;!Isroot(i);i=tr[i].fa) tmp[++ttmp]=tr[i].fa; for (;ttmp;ttmp--) Pushdown(tmp[ttmp]); while (!Isroot(x)){ y=tr[x].fa,z=tr[y].fa; if (!Isroot(y)) tr[y].s[1]==x^tr[z].s[1]==y?Rotate(x):Rotate(y); Rotate(x); } Pushup(x); } void Access(int x){ for (int t=0;x;t=x,x=tr[x].fa) Splay(x),tr[x].s[1]=t,Pushup(x); } void Makeroot(int x){Access(x);Splay(x);Update_rev(x);} int Root(int x){Access(x);Splay(x);while (tr[x].s[0]) x=tr[x].s[0];return x;} void Split(int x,int y){Makeroot(x);Access(y);Splay(y);} void Link(int x,int y){if (Root(x)==Root(y)) return;Makeroot(x);tr[x].fa=y;} void Cut(int x,int y){Split(x,y);if (tr[y].s[0]^x||tr[y].s[1]||tr[x].s[1]) return;tr[y].s[0]=tr[x].fa=0;} int Query_g(int x,int y){Split(x,y);return tr[y].g;} Abigail into(){ scanf("%d%d",&n,&m); for (int i=0;i<=n;i++) tr[i].x=tr[i].min=INF; for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v); } Abigail work(){ sort(e+1,e+1+m); int h=1,cnt=1; for (int i=1;i<=m;i++) tr[i+n].x=e[i].v; for (int i=1;i<=m;i++) if (Root(e[i].x)^Root(e[i].y)){ Link(e[i].x,i+n);Link(e[i].y,i+n); use[i]=1; while (!use[h]) ++h; if (++cnt==n) ans=min(ans,e[i].v-e[h].v); }else{ if (e[i].x==e[i].y) continue; int g=Query_g(e[i].x,e[i].y)-n; Cut(e[g].x,g+n);Cut(e[g].y,g+n); use[g]=0; Link(e[i].x,i+n);Link(e[i].y,i+n); use[i]=1; while (!use[h]) ++h; if (cnt==n) ans=min(ans,e[i].v-e[h].v); } } Abigail outo(){ printf("%d\n",ans); } int main(){ into(); work(); outo(); return 0; }