LuoguP4234_最小差值生成樹_LCT
阿新 • • 發佈:2018-05-06
lin down string.h %d div str i++ oot ESS
LuoguP4234_最小差值生成樹_LCT
題意:
給出一個無向圖,求最大的邊權減最小的邊權最小的一棵生成樹。
分析:
可以把邊權從大到小排序,然後類似魔法森林那樣插入。
如果兩點不連通,直接連上,否則找到兩點間最大的邊權替換。
如果生成一棵樹了就更新答案。
LCT維護邊權的最大值即可。
代碼:
// luogu-judger-enable-o2 #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 400050 #define M 200050 #define ls ch[p][0] #define rs ch[p][1] #define get(x) (ch[f[x]][1]==x) struct A { int x,y,v; }a[N]; bool cmp(const A &x,const A &y){return x.v>y.v;} int ch[N][2],f[N],val[N],siz[N],rev[N],mx[N],tot,n,m,kill[M]; inline bool isrt(int p) { return ch[f[p]][1]!=p&&ch[f[p]][0]!=p; } inline void pushup(int p) { mx[p]=p; if(val[mx[ls]]>val[mx[p]]) mx[p]=mx[ls]; if(val[mx[rs]]>val[mx[p]]) mx[p]=mx[rs]; } inline void pushdown(int p) { if(rev[p]) { swap(ch[ls][0],ch[ls][1]); swap(ch[rs][0],ch[rs][1]); rev[ls]^=1; rev[rs]^=1; rev[p]=0; } } void update(int p) { if(!isrt(p)) update(f[p]); pushdown(p); } void rotate(int x) { int y=f[x],z=f[y],k=get(x); if(!isrt(y)) ch[z][ch[z][1]==y]=x; ch[y][k]=ch[x][!k]; f[ch[y][k]]=y; ch[x][!k]=y; f[y]=x; f[x]=z; pushup(y); pushup(x); } void splay(int x) { update(x); for(int fa;fa=f[x],!isrt(x);rotate(x)) if(!isrt(fa)) rotate(get(x)==get(fa)?fa:x); } void access(int p) { int t=0; while(p) { splay(p); rs=t; pushup(p); t=p; p=f[p]; } } void makeroot(int p) { access(p); splay(p); swap(ls,rs); rev[p]^=1; } void link(int x,int p) { makeroot(x); splay(p); f[x]=p; } void cut(int x,int p) { makeroot(x); access(p); splay(p); ls=f[x]=0; } int find(int p) { access(p); splay(p); while(ls) pushdown(p),p=ls; return p; } int query(int x,int p) { makeroot(x); access(p); splay(p); return mx[p]; } int now=1; int calc() { while(kill[now]&&now<=m) now++; return a[now].v; } int main() { int ans=1<<30; scanf("%d%d",&n,&m); int i; for(i=1;i<=n;i++) mx[i]=i; for(i=1;i<=m;i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v); } sort(a+1,a+m+1,cmp); tot=n; int ne=0; for(i=1;i<=m;i++) { int x=a[i].x,y=a[i].y; tot++; if(x==y) { kill[i]=1; continue; } int dx=find(x),dy=find(y); if(dx!=dy) { ne++; val[tot]=a[i].v; mx[tot]=tot; link(x,tot); link(tot,y); }else { int k=query(x,y); kill[k-n]=1; // printf("%d %d %d\n",k,a[k-n].x,a[k-n].y); cut(a[k-n].x,k); cut(k,a[k-n].y); val[tot]=a[i].v; mx[tot]=tot; link(x,tot); link(tot,y); } if(ne==n-1) { ans=min(ans,calc()-a[i].v); } } printf("%d\n",ans); }
LuoguP4234_最小差值生成樹_LCT