1. 程式人生 > >bzoj1977次小生成樹

bzoj1977次小生成樹

一道複雜一點的倍增題,需要記錄路徑的最大值和第二大值。

注意,嚴格次小生成樹,等生成樹性質要明確

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll ans,f=1;char ch;
    while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';
    while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
    return ans*f;
}
 
 
int n,m,fa[120005];
struct aa
{
    int u,v;
    ll dis;
    bool o;
    bool operator <(const aa &b)const
    {
        return dis<b.dis;
    }
}bian[320005];
int find(int i) { return fa[i]==i?i:fa[i]=find(fa[i]);}
 
 
 
int head[120005],tot;
struct aaa
{
    int to,pre;
    ll dis;
}edge[230005];
void addedge(int u,int v,ll dis)
{
    edge[++tot].to=v;edge[tot].pre=head[u];edge[tot].dis=dis;head[u]=tot;
}


int f[120005][20],dep[120005];ll g1[120005][20],g2[120005][20];

ll se(ll a,ll b,ll c,ll d)
{
	int j;ll t[4]={a,b,c,d};
	sort(t,t+4);
	for (j=3;j>=0;j--) if (t[j]!=t[3]) break;
	if (j==-1) return 0;
	return t[j];
}

void dfs(int u,int depth)
{
    dep[u]=depth;
    for (int i=1;i<=18;i++)
    {
    	int ff=f[u][i-1];
    	f[u][i]=f[ff][i-1];
    	g1[u][i]=max(g1[u][i-1],g1[ff][i-1]);
    	g2[u][i]=se(g1[u][i-1],g1[ff][i-1],g2[u][i-1],g2[ff][i-1]);
	}
    for (int i=head[u];i;i=edge[i].pre)
    if (dep[edge[i].to]==0)
    {
        int v=edge[i].to;
        f[v][0]=u,g1[v][0]=edge[i].dis,g2[v][0]=0;
        dfs(v,depth+1);
    }
}

void updata(ll &fi,ll &se,ll a)
{
	if (a>fi) se=fi,fi=a;
	else if (a==fi) return;
	else if (a>se) se=a;
}

void up(int &u,ll &fi,ll &se,int step)
{
    for (int i=0;i<=18;i++) 
	if (step&(1<<i))
	{
		updata(fi,se,g1[u][i]);updata(fi,se,g2[u][i]);
		u=f[u][i];
	}
}

ll lca(int u,int v,ll dis)
{
    ll se=0,fi=0;
    if (dep[u]>dep[v]) up(u,fi,se,dep[u]-dep[v]);
    else up(v,fi,se,dep[v]-dep[u]);
    
    for (int i=18;i>=0;i--) 
    if (f[u][i]!=f[v][i])
    {
		updata(fi,se,g1[u][i]);updata(fi,se,g1[v][i]);
		updata(fi,se,g2[u][i]);updata(fi,se,g2[v][i]);
        u=f[u][i],v=f[v][i];
    }
    if (u!=v) updata(fi,se,g1[u][0]),updata(fi,se,g1[v][0]);
    if (dis>fi) return fi;else return se;
}
int main()
{
    n=read(),m=read();
    int x,y;ll z;
    for (int i=1;i<=m;i++) bian[i].u=read(),bian[i].v=read(),bian[i].dis=read();
    sort(bian+1,bian+m+1);
    for (int i=1;i<=n;i++) fa[i]=i;
    ll sum=0,ans=1e16;
    for (int i=1;i<=m;i++)
    {
        int fu=find(bian[i].u),fv=find(bian[i].v);
        if (fu!=fv)
        {
            fa[fu]=fv;
            sum+=bian[i].dis;
            bian[i].o=true;
            addedge(bian[i].u,bian[i].v,bian[i].dis);
            addedge(bian[i].v,bian[i].u,bian[i].dis);
        }
    }
    
    dfs(1,1);
    for (int i=1;i<=m;i++)
    if (!bian[i].o)
    {
        ll mx=lca(bian[i].u,bian[i].v,bian[i].dis);
		if (mx!=0) ans=min(sum-mx+bian[i].dis,ans);
    }
    printf("%lld",ans);
    return 0;
}