zoukankan      html  css  js  c++  java
  • 【NOIP 2013 提高组】货车运输

    Luogu 传送门

    简析

    可以发现有一些权值较小的边是不会被走过的。正如样例中的第三条边,就算有其他的很多条边,这条边无论如何也是不会被走过的。于是我们想到了可以将图中这样的边去掉,按照这个思路我们便想到了构造最大生成树,将其余的边去除。

    得到了这样一个树之后,我们便考虑如何求出两个节点之间最小边权的最大值(即为题中的最大载重),因为这两点之间的路径是唯一的,我们只需要找出这条路径便可以得到答案。我们可以通过 LCA 来做到这一点,我求 LCA 的方法是先从每一个根节点进行搜索,求出节点深度等信息,然后利用这些信息进行树上倍增。

    于是我们可以得出大体思路:首先重新建图,构造出最大生成树,然后在最大生成树上求 LCA 来回答询问。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e4+5,M=5e4+5;
    struct edge2 {
    	int u,v,w;
    	bool operator<(const edge2 &x) const {
    		return w>x.w;
    	}
    	edge2() {}
    	edge2(int x,int y,int z) {
    		u=x,v=y,w=z;
    	}
    };
    vector<edge2> v;
    int n,m,fa[N];
    int getf(int x) {
    	return fa[x]==x?x:fa[x]=getf(fa[x]);
    }
    inline void merge(int x,int y) {
    	x=getf(x),y=getf(y),fa[x]=y;
    }
    struct edge {
    	int to,nxt,w;
    } e[N<<1];
    int cnt,head[N];
    inline void add(int u,int v,int w) {
    	e[++cnt].to=v,e[cnt].w=w,e[cnt].nxt=head[u],head[u]=cnt;
    }
    int f[N][30],dep[N],w[N][30];
    bitset<N> vis;
    void build(int u,int fa) {
    	dep[u]=dep[fa]+1,f[u][0]=fa,vis[u]=1;
    	for(int i=head[u]; i; i=e[i].nxt) {
    		int v=e[i].to;
    		if(v==fa) {
    			continue;
    		}
    		w[v][0]=e[i].w,build(v,u);
    	}
    }
    int lca(int x,int y) {
    	if(getf(x)^getf(y)) {
    		return -1;
    	}
    	int ans=1e9;
    	if(dep[x]>dep[y]) {
    		swap(x,y);
    	}
    	for(int i=25; i>=0; i--) {
    		if(dep[f[y][i]]>=dep[x]) {
    			ans=min(ans,w[y][i]),y=f[y][i];
    		}
    	}
    	if(x==y) {
    		return ans;
    	}
    	for(int i=25; i>=0; i--) {
    		if(f[x][i]^f[y][i]) {
    			ans=min(ans,min(w[x][i],w[y][i])),x=f[x][i],y=f[y][i];
    		}
    	}
    	ans=min(ans,min(w[x][0],w[y][0]));
    	return ans;
    }
    int main() {
    	scanf("%d %d",&n,&m);
    	for(int i=0,x,y,z; i<m; i++) {
    		scanf("%d %d %d",&x,&y,&z),v.push_back(edge2(x,y,z));
    	}
    	sort(v.begin(),v.end());
    	for(int i=1; i<=n; i++) {
    		fa[i]=i;
    	}
    	int sum=1;
    	for(int i=0; i<m; i++) {
    		int x=v[i].u,y=v[i].v,z=v[i].w;
    		if(getf(x)^getf(y)) {
    			merge(x,y),add(x,y,z),add(y,x,z),sum++;
    		}
    		if(sum==n) {
    			break;
    		}
    	}
    	for(int i=1; i<=n; i++) {
    		if(!vis[i]) {
    			build(i,0),w[i][0]=1e9;
    		}
    	}
    	for(int i=1; i<=25; i++) {
    		for(int j=1; j<=n; j++) {
    			f[j][i]=f[f[j][i-1]][i-1],w[j][i]=min(w[j][i-1],w[f[j][i-1]][i-1]);
    		}
    	}
    	int q;
    	scanf("%d",&q);
    	for(int i=1,x,y; i<=q; i++) {
    		scanf("%d %d",&x,&y),printf("%d
    ",lca(x,y));
    	}
    	return 0;
    }
    

    本文作者:AFewMoon,文章地址:https://www.cnblogs.com/AFewMoon/p/15186779.html

    知识共享许可协议

    本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

    限于本人水平,如果文章有表述不当之处,还请不吝赐教。

  • 相关阅读:
    GIT笔记
    C++新式类型转换
    C++ 静态链表基本算法实现
    C++ 顺序栈基本算法实现
    C++ 链栈 基本算法实现
    C++ 循环队列基本算法实现
    C++ 链队列基本算法实现
    C++优先级队列表基本算法实现
    C++单链表基本算法实现
    C++ 循环链表基本算法
  • 原文地址:https://www.cnblogs.com/Sam2007/p/15186779.html
Copyright © 2011-2022 走看看