• [luogu1967] 货车运输


    题面

    ​ 这个题目第一眼看觉得是道最短路,但是一看数据范围,有3e5次询问,1e5个点,所以最终用上dijkstra的时间复杂度便是:

    \[O(qn ^ 2) \]

    加上堆优化之后也只有:

    \[O(qn\log_{2}^{n}) \]

    所以,我们肯定只能用别的方法来做了。

    ​ 继续看题,题目中如是说道:"司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。", 又这样说道:"x 不等于 y,两座城市之间可能有多条道路 。" 这句话是很重要的,它说明了若是x, y之间有多余的边,那么只取其中最长的那条边就是了, 所以这就是最大生成树了, 因为两两之间只有一条边。

    等会, 好像还是有点问题

    ​ 若两个点之间不联通呢??? 那我们就不建树, 建一棵最大生成森林就可以了, 如果询问的两个点不在同一棵树中的话,就输出不成立。至于查询两点间的距离的话, 不是LCA的模版题吗, 这道题就被我们完美(莫名其妙)地解决了。所以,一个题只要剖析清楚,其实就没有那么难了。

    代码

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define N 100005
    #define M 500005
    using namespace std;
    
    int n, m, head[N], cnt, fa[N], tot, rnk[N], f[N][25], dis[N][25], dep[N], q;
    struct node
    {
    	int to, from, cost, next; 
    } edge[M << 1], e[N << 1]; 
    
    inline int read()
    {
    	int x = 0, w = 1;
    	char c = getchar();
    	while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
    	while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    	return x * w;
    }
    
    inline void add(int u, int v, int w) { edge[++cnt].to = v; edge[cnt].from = u; edge[cnt].next = head[u]; edge[cnt].cost = w; head[u] = cnt; }
    
    inline void adde(int u, int v, int w) { e[++tot].to = v; e[tot].from = u; e[tot].cost = w; e[tot].next = head[u]; head[u] = tot; }
    
    inline bool cmp(node a, node b) { return a.cost > b.cost; }
    
    inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
    
    inline void merge(int x, int y)
    {
    	x = find(x); y = find(y);
    	if(rnk[x] < rnk[y]) fa[x] = y; 
    	else if(rnk[x] > rnk[y]) fa[y] = x;
    	else { fa[x] = y; rnk[y]++; }
    }
    
    inline void Kruskal()
    {
    	memset(head, 0, sizeof(head)); 
    	for(int i = 1; i <= n; i++) { fa[i] = i; rnk[i] = 1; }
    	sort(edge + 1, edge + cnt + 1, cmp); 
    	for(int i = 1; i <= cnt; i++)
    	{
    		int u = edge[i].from, v = edge[i].to; 
    		int r1 = find(u), r2 = find(v);
    		if(r1 != r2)
    		{
    			merge(r1, r2);
    			adde(u, v, edge[i].cost); adde(v, u, edge[i].cost); 
    		}
    	}
    }
    
    inline void dfs(int u, int fa)
    {
    	f[u][0] = fa; dep[u] = dep[fa] + 1; 
    	for(int i = 1; i <= 20 && f[f[u][i - 1]][i - 1]; i++)
    	{
    		f[u][i] = f[f[u][i - 1]][i - 1];
    		dis[u][i] = min(dis[u][i - 1], dis[f[u][i - 1]][i - 1]); 
    	}
    	for(int i = head[u]; i; i = e[i].next)
    	{
    		int v = e[i].to; if(v == fa) continue;
    		dis[v][0] = e[i].cost; dfs(v, u); 
    	}
    }
    
    inline int lca(int u, int v)
    {
    	if(dep[u] > dep[v]) swap(u, v);
    	int ans = 1e9;
    	for(int i = 18; i >= 0; i--)
    		if(dep[f[v][i]] >= dep[u])
    		{
    			ans = min(ans, dis[v][i]); 
    			v = f[v][i]; 
    		}
    	if(u == v) return ans;
    	for(int i = 20; i >= 0; i--)
    		if(f[u][i] != f[v][i])
    		{
    			ans = min(ans, min(dis[v][i], dis[u][i]));
    			v = f[v][i]; u = f[u][i]; 
    		}
    	ans = min(ans, min(dis[v][0], dis[u][0]));
    	return ans; 
    }
    
    int main()
    {
    	memset(f, 0, sizeof(f)); 
    	n = read(); m = read();
    	for(int i = 1; i <= m; i++)
    	{
    		int u = read(), v = read(), w = read();
    		add(u, v, w); 
    	}
    	Kruskal(); 
    	for(int i = 1; i <= n; i++)
    		if(!dep[i])
    			dfs(i, 0); 
    	q = read(); 
    	for(int i = 1; i <= q; i++)
    	{
    		int x = read(), y = read(); 
    		if(find(x) != find(y)) { puts("-1"); continue; }
    		printf("%d\n", lca(x, y)); 
    	}
    	return 0;
    }
    

  • 相关阅读:
    Codeforces 812E Sagheer and Apple Tree
    bzoj 4765: 普通计算姬
    bzoj 4552: [Tjoi2016&Heoi2016]排序
    bzoj 1096: [ZJOI2007]仓库建设
    bzoj 1030: [JSOI2007]文本生成器
    bzoj 1095: [ZJOI2007]Hide 捉迷藏
    JS实现HashMap
    A4纸表格打印
    JAVA字符串格式化-String.format()的使用
    证书打印CSS知识点总结
  • 原文地址:https://www.cnblogs.com/ztlztl/p/10403565.html
Copyright © 2020-2023  润新知