bzoj1977: [BeiJing2010]次小生成树 kruskal+倍增LCA

给定一张无向图,求严格次小的生成树(保证存在)

非严格次小的很好做

kruskal求出最小生成树,倍增求LCA与区间最大边权

枚举剩下的边两端点之间的最大值比较即可.

但是要严格次小的话,要在倍增时维护一个次大边权值

枚举时如果当前边与最大相等则比较次大

做的时候一堆奇怪的bug。。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=100004,M=300005;
struct Edge{
	int u,v,nex,flag;LL w;
}e[M*2],edge[M*2];
int n,m,tot,head[N],fa[N][20],dep[N],pa[N];
LL ma[N][20],m2[N][20],sum;
inline void Addedge(int u,int v,LL w)
{
	edge[++tot].v=v;edge[tot].nex=head[u];edge[tot].w=w;head[u]=tot;
}
bool cmp(const Edge &a,const Edge &b)
{
	return a.w<b.w;
}
int find(int v)
{
	if(pa[v]==v)return v;
	return pa[v]=find(pa[v]);
}
void kruskal()
{
	int cnt=0;
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=n;i++)pa[i]=i;
	for(int i=1;i<=m;i++)
	{
		if(cnt==n-1)break;
		int x=find(e[i].u),y=find(e[i].v);
		if(x!=y){
			pa[x]=y;sum+=e[i].w;cnt++;
			Addedge(e[i].u,e[i].v,e[i].w);
			Addedge(e[i].v,e[i].u,e[i].w);
			e[i].flag=1;
			//e[i].nex=head[e[i].u];head[e[i].u]=i;
		}
	}
}

void dfs(int u,int f)
{
	for(int i=1;i<=19;i++){
		int ff=fa[u][i-1];
		fa[u][i]=fa[ff][i-1];
		ma[u][i]=max(ma[u][i-1],ma[ff][i-1]);
		//m2[u][i]=getsec(ma[u][i-1],m2[u][i-1],ma[ff][i-1],m2[ff][i-1]);
		m2[u][i]=max(m2[u][i-1],m2[ff][i-1]);
		if(ma[u][i-1]!=ma[ff][i-1])
		  m2[u][i]=max(m2[u][i],min(ma[u][i-1],ma[ff][i-1]));
	}
	for(int i=head[u];i;i=edge[i].nex){
		int v=edge[i].v,w=edge[i].w;
		if(v==f)continue;
		fa[v][0]=u;ma[v][0]=w;dep[v]=dep[u]+1;
		dfs(v,u);
	}
}


int LCA(int x,int y)
{
	if(dep[x]<dep[y])swap(x,y);
	for(int i=19;i>=0;i--)
	  if(dep[fa[x][i]]>=dep[y])
	    x=fa[x][i];
	if(x==y)return x;
	for(int i=19;i>=0;i--)
	  if(fa[x][i]!=fa[y][i])
	    x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
LL ans=(1LL<<40);
void cal(int x,int lca,LL v)
{
	LL c1=0,c2=0;
	int h=dep[x]-dep[lca];
	for(int i=19;i>=0;i--)if(h&(1<<i))
	{
		if(ma[x][i]>c1)
		  c2=c1,c1=ma[x][i];
		c2=max(c2,m2[x][i]);
		h-=(1<<i);
	}
	if(v==c1)ans=min(ans,v-c2);
	else ans=min(ans,v-c1);
}
void ask(int x,int y,LL len)
{
	int lca=LCA(x,y);
	cal(x,lca,len);cal(y,lca,len);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,u,v,w;i<=m;i++){
		scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);
	}
	kruskal();
	dfs(1,0);
	for(int i=1;i<=m;i++)
	{
		if(e[i].flag)continue;
		ask(e[i].u,e[i].v,e[i].w);
	}
	printf("%lld\n",sum+ans);
	return 0;
}



猜你喜欢

转载自blog.csdn.net/wolf_reiser/article/details/78880877