zoukankan      html  css  js  c++  java
  • 【洛谷P1967】货车运输

    题目

    题目链接:https://www.luogu.com.cn/problem/P1967
    A 国有 (n) 座城市,编号从 $1 $ 到 $ n$,城市之间有 (m) 条双向道路。每一条道路对车辆都有重量限制,简称限重。

    现在有 (q) 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

    思路

    Kruskal 重构树模板题。
    Kruskal 重构树一般解决的问题是“给出一张无向图,询问 (x,y) 两点之间所有路径中最短边长度最长的边的长度”。
    我们将边权从大到小排序,在 Kruskal 求最大生成树时,如果 (x',y') 两点并查集的根节点 (x,y) 不同,那么就建立一个新点 (p),从 (p) 分别向 (x)(y) 连边,然后将 (x,y) 两者的父亲都指向 (p)。点 (p) 的点权即为这条边的长度。
    这样对于一组询问 (x,y),我们直接在 Kruskal 重构树上求出其 LCA,答案显然就是该点的权值。
    时间复杂度 (O(Qlog n+m))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=20010,M=50010,LG=18;
    int n,m,Q,tot,val[N],head[N],father[N],dep[N],f[N][LG+1];
    
    struct edge1
    {
    	int u,v,dis;
    }e1[M];
    
    struct edge2
    {
    	int next,to;
    }e2[M];
    
    void add(int from,int to)
    {
    	e2[++tot]=(edge2){head[from],to};
    	head[from]=tot;
    }
    
    bool cmp(edge1 x,edge1 y)
    {
    	return x.dis>y.dis;
    }
    
    int find(int x)
    {
    	return x==father[x]?x:father[x]=find(father[x]);
    }
    
    void kruskal()
    {
    	sort(e1+1,e1+1+m,cmp);
    	for (int i=1;i<n*2;i++) father[i]=i;
    	for (int i=1;i<=m;i++)
    	{
    		int x=find(e1[i].u),y=find(e1[i].v);
    		if (x!=y)
    		{
    			n++; val[n]=e1[i].dis;
    			add(n,x); add(n,y);
    			father[x]=father[y]=n;
    		}
    	}
    }
    
    void dfs(int x,int fa)
    {
    	dep[x]=dep[fa]+1; f[x][0]=fa;
    	for (int i=1;i<=LG;i++)	
    		f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=head[x];~i;i=e2[i].next)
    		dfs(e2[i].to,x);
    }
    
    int lca(int x,int y)
    {
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int i=LG;i>=0;i--)
    		if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    	if (x==y) return x;
    	for (int i=LG;i>=0;i--)
    		if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;i++)
    		scanf("%d%d%d",&e1[i].u,&e1[i].v,&e1[i].dis);
    	kruskal();
    	for (int i=1;i<=n;i++)
    		if (find(i)==i) dfs(i,0);
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		if (find(x)!=find(y)) printf("-1
    ");
    			else printf("%d
    ",val[lca(x,y)]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    php 实现店铺装修3
    脸如何瘦
    第一次约会看电影的细节 了解好男人的标准看他是否合格
    14细节 看男人爱你到什么程度:第一次约会时他沉默寡言
    男生第一次约会穿什么?
    提高心理素质 2
    心理素质差的原因
    如何提高心理素质
    不适合做老婆的女人,五大特质(转载)
    心理素质差的表现
  • 原文地址:https://www.cnblogs.com/stoorz/p/14082447.html
Copyright © 2011-2022 走看看