洛谷P1967货车运输

这道题 首先不难看出要先求一个最大生成树,因为我们在尽量图联通的情况下,使两点之间有一条权值最大的边,所以Kru跑一遍最大生成树;

然后会有很显然的事情就是裸的生成树只能求总和,但我们需要知道树上有哪条边,所以在合并两个联通块时,将两个端点以及他们间的边加入另一个图中,那么显然新图中只包含最大生成树上的边,然后就是求两点之间的最长边,一个比较暴力的做法是floyed求任意两点间的最长边,但我们观察到点数<=10000,floyed显然不可取,那么正解是什么呢?

倍增Lca,我们不难发现,如果两个点联通的话,那么从两个点出发,必定会交于一点,显然这个点是他们的公共祖先,所以预处理每个点到他的祖先的最长边,询问时,再跑lca就可以啦

代码 1400ms
//By AcerMo

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int M=100500;
struct edge
{
	int from,to,cost;
	bool friend operator < (edge a,edge b)
	{
		return a.costq;
struct map
{
	int to,cost;
}_233;//新图 
vectorv[M];
int n,m,que;
int vis[M],deep[M],pt[M][21];
int fa[M],size[M],fatt[M][21];
int find(int x)
{
	if (x!=fa[x]) return fa[x]=find(fa[x]);
	return x;
}
void unionn(int a,int b)
{
	if (size[a]<=size[b]) size[b]+=size[a],fa[a]=b;
	else size[a]+=size[b],fa[b]=a;
	return ;
}//加入了按秩合并以及路径压缩 
void constt()
{
	for (int i=0;i<=n;i++)
	size[i]=1,fa[i]=i,fatt[i][0]=i,pt[i][0]=M<<5;
	return ;
}//初始化每个点的信息 
void kru()
{
	int cnt=1;constt();
	while (q.size()&&cntdeep[y]) swap(x,y);
	for (int i=20;i>=0;i--)
		if (deep[fatt[y][i]]>=deep[x]) 
			ans=min(ans,pt[y][i]),y=fatt[y][i];
	if (x==y) return ans;
	for (int i=20;i>=0;i--)
		if (fatt[x][i]!=fatt[y][i])
			ans=min(ans,min(pt[x][i],pt[y][i])),
				x=fatt[x][i],y=fatt[y][i];
	ans=min(ans,min(pt[x][0],pt[y][0]));
	return ans;
}//lca求解 
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
		scanf("%d%d%d",&now.from,&now.to,&now.cost),q.push(now);
	kru();scanf("%d",&que);
	for (int i=1;i<=n;i++)
	if (!vis[i]) getlca(i);
	getminpath();
	while (que--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		int ans=lca(x,y);
		cout<

你可能感兴趣的:(图论-最小生成树,倍增LCA)