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;
    }
    
  • 相关阅读:
    oracle数据库性能优化 降低IO
    用bat文件设置程序启动环境
    我的go语言上机测试代码
    解决golang.org不能访问的问题
    go语言 windows 32位编译环境搭建
    JQueryEasyUI学习笔记(十一)datagrid 右键菜单,冻结列
    JQueryEasyUI学习笔记(十二)datagrid 提示、格式化表格、表格按钮(附源码)
    JQueryEasyUI学习笔记(十四)tree
    JQueryEasyUI学习笔记(十三) 更换主题皮肤
    JQueryEasyUI学习笔记(七)datagrid
  • 原文地址:https://www.cnblogs.com/stoorz/p/14082447.html
Copyright © 2011-2022 走看看