【NOIP 2013】货车运输(Kruskal+lca)

传送门

Solution:###

一辆车的载重,取决于他到终点上的路的载重最小值,最小值越大,装的就越多

考虑如何找路径,如果bfs或者dfs的话,TLE。

这时想到,我们可以做一颗最大生成树(按照权值从大到小排序),在生成树的基础上,两点之间都是联通的,而且载重也是最优的。

这时考虑如何在生成树上找到两点的路径,一棵树,自然而然地就想到了LCA,然后就AC了。

#include<bits/stdc++.h>
#define N 10005
#define M 50005
using namespace std;
int n,m,father[N],tot,first[N],dep[N],up[N][22],w[N][22];
const int INF=0x7fffffff;
struct A
{
	int from,to,val;
}a[M];
struct node
{
	int to,next,val;
}edge[2*M];
inline int getfather(int x)
{
	if(father[x]==x)	return x;
	father[x]=getfather(father[x]);
	return father[x];
}
inline void addedge(int x,int y,int z)
{
	tot++;
	edge[tot].to=y;
	edge[tot].next=first[x];
	edge[tot].val=z;
	first[x]=tot;
}
inline bool cmp(const A &x,const A &y)
{
	return x.val>y.val;
}
void Init()
{
	for(int i=1;i<=n;i++)
	{
		father[i]=i;
	}	
}
void kruskal()
{
	int k=0;
	for(int i=1;i<=m;i++)
	{
		int x=a[i].from;
		int y=a[i].to;
		int ax=getfather(x);
		int bx=getfather(y);
		if(ax!=bx)
		{
			father[ax]=bx;
			k++;
			addedge(x,y,a[i].val);
			addedge(y,x,a[i].val);
		}
		if(k==n-1)	break;
	}
}
inline void dfs(int now)
{
	for(int u=first[now];u;u=edge[u].next)
	{
		int vis=edge[u].to;
		if(dep[vis])	continue;
		dep[vis]=dep[now]+1;
		up[vis][0]=now;
		w[vis][0]=edge[u].val;
		dfs(vis);
	}
}
inline int lca(int x,int y)
{
	if(getfather(x)!=getfather(y))	return -1;
	if(dep[x]<dep[y])	swap(x,y);
	int ans=INF;
	for(int i=20;i>=0;i--)//注意是到0,而不是1,是1就WA了
	{
		if(dep[up[x][i]]>=dep[y])
		{
			ans=min(ans,w[x][i]);
			x=up[x][i];
		}
	}
	if(x==y)	return ans;
	for(int i=20;i>=0;i--) 
	{
		if(up[x][i]!=up[y][i])
		{
			ans=min(ans,min(w[x][i],w[y][i]));
			x=up[x][i];
			y=up[y][i];
		}
	}
	ans=min(ans,min(w[x][0],w[y][0]));
	return ans;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cin>>n>>m;
	Init();
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		a[i].from=x,a[i].to=y,a[i].val=z;
	}
	sort(a+1,a+m+1,cmp);
	kruskal();
	
	for(int i=1;i<=n;i++)//由于不确定生成树包含哪些点 所以要一个一个扫描 
	{
		if(!dep[i])
		{
			dep[i]=1;
			dfs(i);
			up[i][0]=i;
			w[i][0]=INF;
		}
	}
	
	for(int j=1;j<=20;j++)
	{
		for(int i=1;i<=n;i++)
		{
			up[i][j]=up[up[i][j-1]][j-1];
			w[i][j]=min(w[i][j-1],w[up[i][j-1]][j-1]);
		}
	}
	int q;
	cin>>q;
	for(int i=1;i<=q;i++)
	{
		int x,y;
		cin>>x>>y;
		cout<<lca(x,y)<<'\n';
	}
	return 0;
}
posted @ 2018-07-31 14:46  Patrickpwq  阅读(89)  评论(0编辑  收藏  举报