1. 程式人生 > >邊權差值最小的生成樹

邊權差值最小的生成樹

題目p1223

https://www.luogu.org/problemnew/show/P4234

程式碼

小資料版

使用Kruskal演算法的評測結果:
https://www.luogu.org/recordnew/show/15314074

//小資料版 已經極致優化,然而還是T掉最後一個點,T_T
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
char buf[1<<15],*fs,*ft;
inline char getc(){return (ft==fs&&
(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++;} inline int read() { int num=0,f=1;char ch=getchar(); while (!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) num=(num<<3)+(num<<1)+(ch^48), ch=getchar(); return num*f; } inline void print(int x)//快寫 { if
(x<0) putchar('-'),x=-x; if (x>9) print(x/10); putchar(x%10+48); return ; } struct rec { int x,y,z; }edge[maxn]; int fa[maxn],ans; inline bool operator < (rec a,rec b) { return a.z<b.z; } inline int get(int x) { if (x==fa[x]) return x; return fa[x]=get(fa[x]); } int main() { int
n=read(),m=read(),i=0; if (n==1) { puts("0"); exit(0); } for (i=1;i<=m;++i) edge[i].x=read(),edge[i].y=read(),edge[i].z=read(); sort(edge+1,edge+m+1); ans=edge[m].z;//差值初始化 for (int k=1;k<=m;++k)//以k為最小邊進行列舉 { int sum=0;//最小生成樹的邊數 for (i=1;i<=n;++i)//生成樹初始化 fa[i]=i; for (i=k;i<=m;++i)//求最小生成樹 { int x=get(edge[i].x); int y=get(edge[i].y); if (x==y) continue; fa[x]=y; ++sum; if (sum==n-1)//已構成一個最小生成樹(從定義出發) { ans=min(ans,edge[i].z-edge[k].z);//最大邊減去最小邊 break; } } if (i==m+1) break; } if (ans==edge[m].z)//ans未經過改變,說明此圖未連通 puts("-1"); else print(ans); return 0; }

正解

一個叫做LCT的神奇演算法,評測結果:
https://www.luogu.org/recordnew/show/15314276

#include<bits/stdc++.h>
#define up(i,a,b) for (register int i=a;i<=b;++i)
#define down(i,a,b) for (register int i=a;i>=b;--i)
using namespace std;
template<typename T>inline void read(T &x)
{
    T s=0,f=1;
	char ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (!isdigit(ch)) { f=-1; ch=getchar(); }
    while (isdigit(ch)) s=(s<<1)+(s<<3)+(ch^48), ch=getchar();
    x=s*f;
}
static int n,m;
const int maxn=8e5+7;
static struct edge
{
    int u,v,w;
    friend bool operator < (edge a,edge b)
	{
		return a.w>b.w;
	}
}q[maxn];
inline void init()
{
    read(n),read(m);
    if (n==1)
	{
		puts("0");
		exit(0);
	}
    for (register int i=1;i<=m;++i)
    {
        read(q[i].u),read(q[i].v),read(q[i].w);
        if (q[i].u==q[i].v)
			--i,--m;
    }
    sort(q+1,q+m+1);
}
namespace LCT
{
    int p[maxn],son[maxn][2],fa[maxn],key[maxn],rev[maxn];
    inline bool isroot(int x)
    {
		return x!=son[fa[x]][0] && x!=son[fa[x]][1];
	}
    inline void refresh(int x)
    {
        p[x]=p[ son[x][ key[ p[son[x][0]] ]>key[ p[son[x][1]] ] ? 0 : 1 ] ];
        if (key[x]>key[p[x]]) 
			p[x]=x;
    }
    inline bool isl(int x)
	{
		return x^son[fa[x]][0];
	}
    inline void rotate(int x)
    {
        static int f,ff,ke;
		f=fa[x],ff=fa[f],ke=isl(x);
        fa[x]=ff;
		if (!isroot(f))
			son[ff][isl(f)]=x;
        son[ fa[son[x][ke^1]]=f ][ke]=son[x][ke^1];
        son[ fa[f]=x ][ke^1]=f;
        refresh(f),refresh(x);
    }
    inline void pushdown(int x)
    {
        if (rev[x])
        	swap(son[x][0],son[x][1]),
			rev[son[x][0]]^=1,rev[son[x][1]]^=1,
        	rev[x]=0;	
    }

    static int sta[maxn];
    inline void splay(int x)
    {
        static int t,top,f;
		sta[top=1]=x;
        for (t=x;!isroot(t);t=fa[t])
			sta[++top]=fa[t];
        for (;top;--top)
			pushdown(sta[top]);
        for (f=fa[x];!isroot(x);rotate(x),f=fa[x])
            if (!isroot(f))
				rotate(isl(x)^isl(f)?x:f);
    }

    inline void access(int x)
    {
        static int t;
        for(t=0;x;t=x,x=fa[x])
            splay(x),son[x][1]=t,refresh(x);
    }
    inline void makeroot(int x)
    {
		access(x),splay(x),rev[x]^=1;
	}
    inline void link(int x,int y)
    {
		makeroot(x),fa[x]=y;
	}
    inline void cut(int x,int y)
    {
        makeroot(x),access(y),splay(y);
        son[y][0]=fa[x]=0,refresh(y);
    }
    inline int find(int x)
    {
        access(x),splay(x);
        while (son[x][0])	x=son[x][0];
        return x;
    }
}
using namespace LCT;
multiset<int,greater<int> >G;
multiset<int,greater<int> >::iterator it;
#define Chkmin(a,b) a=a<b?a:b   
inline void solve()
{
    static int ans=200000,cnt=0,poi;
    up (i,1,m)
		key[i+n]=q[i].w;
    up (i,1,m)
    {
        if (find(q[i].u)==find(q[i].v))
        {
            makeroot(q[i].u),access(q[i].v),splay(q[i].v);
            poi=p[q[i].v];
            cut(poi,q[poi-n].u);
            cut(poi,q[poi-n].v);
            key[poi]=0;
            it=G.lower_bound(q[poi-n].w);
            G.erase(it);
        }
		else ++cnt;
        link(q[i].u,i+n);
        link(q[i].v,i+n);
        G.insert(q[i].w);
        if	(cnt==n-1)
			Chkmin(ans,*G.begin()-q[i].w);
    }
    printf("%d\n",ans);
}
int main()
{
    init();
    solve();
    return 0;
}