• [NOIp2013] 货车运输 题解


    这题好。结论非常清新。

    给你一个 (n) 个点的图,共有 (m) 条边。有 (q) 次询问,每次询问两点 (x)(y),求从 (x)(y) 的最小路径最大值。

    kruskal 构造最大生成树,将其余的边去除。在这棵最大生成树上跑 LCA 就可以了,dfs 时统计到 (2^i) 级的祖先的最小路径最大值,求 LCA 一并整合就好了。

    实现细节多的很。具体看代码。

    #include <iostream>
    #include <cstdio>
    #include <algorithm> 
    using namespace std;
    const int maxm = 50005, maxn = 50005;
    const int inf = 0x7f7f7f7f;
    struct edge1 {		//原图
    	int x, y, val;
    } org[maxm];
    struct edge2 {		//最大生成树图
    	int to, nxt, val;
    } e[maxm * 2];
    inline bool cmp(edge1 a, edge1 b) { return a.val > b.val; }
    inline void swp(int &a, int &b) { a^= b ^= a ^= b; }
    inline int minn(int a, int b) { return a & ((a - b) >> 31) | b & (~(a - b) >> 31); }
    int n, m, head[maxn], cnt, fa[maxn][22], dep[maxn], lg[maxn], t;	// LCA 的数组
    int f[maxm], w[maxm][22];	//fa 是 dsu 的数组,w 表示最大载重
    bool vis[maxn];				//vis 是不连通化扫描
    int find(int x) {
        if(f[x] != x) f[x] = find(f[x]);
        return f[x];
    }
    void add(int u, int v, int w) {
    	e[++ cnt].to = v;
    	e[cnt].val = w;
    	e[cnt].nxt = head[u];
    	head[u] = cnt;
    }
    void kruskal() {
    	sort(org + 1, org + 1 + m, cmp);
    	for(int i = 1; i <= n; i ++) f[i] = i;
    	for(int i = 1; i <= m; i ++) {
    		if(find(org[i].y) != find(org[i].x)) {
    			f[find(org[i].x)] = find(org[i].y);
    			add(org[i].y, org[i].x, org[i].val);
    			add(org[i].x, org[i].y, org[i].val);
    		}
    	}
    }
    void dfs(int now, int father, int weight) {
    	vis[now] = 1;
    	fa[now][0] = father;
    	dep[now] = dep[father] + 1;
    	w[now][0] = weight;
    	for(int i = 1; (1 << i) <= dep[now]; i ++) {
    		fa[now][i] = fa[fa[now][i - 1]][i - 1];
    		w[now][i] = minn(w[now][i - 1], w[fa[now][i - 1]][i - 1]);
    	} for(int i = head[now]; i; i = e[i].nxt) if(e[i].to != father) dfs(e[i].to, now, e[i].val);
        return;
    }
    int LCA(int x, int y) {
        if (find(x) != find(y)) return -1;
    	int ans = inf;
    	if(dep[x] < dep[y]) swp(x, y);
    	while(dep[x] > dep[y]) {
            ans = minn(ans, w[x][lg[dep[x] - dep[y]] - 1]);
    		x = fa[x][lg[dep[x] - dep[y]] - 1];
    	} if(x == y) return ans;
    	for(int k = lg[dep[x]] - 1; k >= 0; k --) 
    		if(fa[x][k] != fa[y][k]) {
                ans = minn(minn(ans, w[x][k]), w[y][k]);
    			x = fa[x][k], y = fa[y][k];
            }
    	ans = minn(minn(ans, w[x][0]), w[y][0]);
    	return ans;
    }
    int main() {
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= m; i ++) scanf("%d%d%d", &org[i].x, &org[i].y, &org[i].val);
    	for(int i = 1; i <= n; i ++) lg[i] = lg[i-1] + (1 << lg[i-1] == i);
    	kruskal();
    	for(int i = 1; i <= n; i ++) if(!vis[i]) dfs(i, 0, 0);
    	scanf("%d", &t);
    	while(t --) {
    		int x, y;
    		scanf("%d%d", &x, &y);
    		printf("%d
    ", LCA(x, y));
    	}
    }
    

    学你妈,还有两天就要 CSP 了老子才开始复习

  • 相关阅读:
    《Java从入门到放弃》入门篇:Struts2的基本数据传递方式
    《Java从入门到放弃》入门篇:Struts2的常用基本标签
    《Java从入门到放弃》入门篇:Struts2的基本访问方式(二)
    《Java从入门到放弃》入门篇:Struts2的基本访问方式
    《Java从入门到放弃》入门篇:XMLHttpRequest的基本用法
    Unity 从StreamingAssets文件夹和PersistentData文件夹 保存读取AssetBundle资源 路径详解
    海外版本修改总结
    unity A*寻路 (三)A*算法
    unity A*寻路 (二)读取NavMesh数据
    unity A*寻路 (一)导出NavMesh数据
  • 原文地址:https://www.cnblogs.com/Inversentropir-36/p/13931700.html
Copyright © 2020-2023  润新知