[题解]P1967[NOIP2013 提高组] 货车运输

基本思路#

因为这道题要我们求两点之间任意一条路径上最大的最小点,所以我们建图的时候就可以用kruskal算法来建一棵最大生成树,把一些不必要的边去掉,这样建图的问题就解决了。

接着我们就要求出每个点的深度,倍增求lca中的fa数组...但是题目中有一句话“如果货车不能到达目的地,输出 -1”,这句话告诉我们,不一定只有一棵树,那么我就要进行染色处理联通快

代码:

  for(int i=1;i<=n;i++){
    if(!vis[i]){
      dep[i]=1;
      dfs(i);
      fa[i][0]=i;
      w[i][0]=inf;
  }

从上面的代码我们用了w数组,它表示某一段路上的最小值,我们可以这样来对它进行初始化:

w[j][i]=min(w[j][i1],w[fa[j][i1]][i1])

代码#

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
struct node{
  int x,y,z;
}edgee[50005];
int fa[10005][25],w[10005][25],dep[10005];
int tot,edge[100005],ver[100005],head[100005],nxt[100005];
bool vis[10005];
int f[10005],q,n,m;
const int inf=0x3f3f3f3f;
inline int read(){
  int x=0,f=1;char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
  while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
  return x*f;
}
inline bool cmp(node a,node b){
  return a.z>b.z;
}
inline int find(int x){
  if(f[x]==x) return x;
  return f[x]=find(f[x]);
}
inline void add(int x,int y,int z){
  ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;
}
inline void dfs(int num){
  vis[num]=true;
  for(int i=head[num];i;i=nxt[i]){
    int to=ver[i];
    if(vis[to]) continue;
    dep[to]=dep[num]+1;
    fa[to][0]=num;
    w[to][0]=edge[i];
    dfs(to);
  }
  return;
}
inline int lca(int x,int y){
  int ans=inf;
  if(find(x)!=find(y)) return -1;//不连通
  if(dep[x]<dep[y]) swap(x,y);
  for(int i=20;i>=0;i--){
    if(dep[fa[x][i]]>=dep[y]){
      ans=min(ans,w[x][i]);
      x=fa[x][i];
    }
  }
  if(x==y) return ans;
  for(int i=20;i>=0;i--){
    if(fa[x][i]!=fa[y][i]){
      ans=min(ans,w[x][i]);
      ans=min(ans,w[y][i]);
      x=fa[x][i];
      y=fa[y][i];
    }
  }
    ans=min(ans,w[x][0]);
    ans=min(ans,w[y][0]);
    return ans;
}
int main(){
  n=read();m=read();
  for(int i=1;i<=m;i++){
    edgee[i].x=read();
    edgee[i].y=read();
    edgee[i].z=read();
  }
  sort(edgee+1,edgee+1+m,cmp);
  for(int i=1;i<=n;i++)
    f[i]=i;
  for(int i=1;i<=m;i++)
    {
      int xx=find(edgee[i].x);
      int yy=find(edgee[i].y);
      if(xx==yy) continue;
      add(edgee[i].x,edgee[i].y,edgee[i].z);
      add(edgee[i].y,edgee[i].x,edgee[i].z);
      f[xx]=yy;
    }
  for(int i=1;i<=n;i++){
    if(!vis[i]){
      dep[i]=1;
      dfs(i);
      fa[i][0]=i;
      w[i][0]=inf;
  }
  }
  for(int i=1;i<=20;i++)
    for(int j=1;j<=n;j++)
      {
	fa[j][i]=fa[fa[j][i-1]][i-1];
	w[j][i]=min(w[j][i-1],w[fa[j][i-1]][i-1]);
      }
  q=read();
  for(int i=1;i<=q;i++){
    int x,y;
    x=read();y=read();
    cout<<lca(x,y)<<endl;
  }
  return 0;
}
posted @   Miraii  阅读(198)  评论(1编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩