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;
    }
    
  • 相关阅读:
    实现倒计时
    slidingMenu使用中侧滑回界面后,出现无焦点问题
    android eclipse 下Device无设备问题解决
    android cordova java.lang.Throwable: EventHub.removeMessages(int what = 107) is not supported before the WebViewCore is set up问题的解决和想法
    Android Cordova 对于软键盘弹出后覆盖输入域的解决
    Extjs最后一页数据删除之后自动返回上一页
    jquery Unexpected token i
    批量删除.svn文件夹、.svn文件
    mysql创建用户权限
    mysql存储过程解决数组传参及游标CURSOR的问题解决方案
  • 原文地址:https://www.cnblogs.com/stoorz/p/14082447.html
Copyright © 2011-2022 走看看