社区讨论

10分求助,萌新刚学c++ 1s

P1967[NOIP 2013 提高组] 货车运输参与者 3已保存回复 7

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
7 条
当前快照
1 份
快照标识符
@lobv8ajt
此快照首次捕获于
2023/10/30 03:30
2 年前
此快照最后确认于
2023/11/04 08:32
2 年前
查看原帖
CPP
#include <iostream>
#include <algorithm>
#include <climits>
using namespace std;
const int kMaxN=1e4+1;
const int kMaxM=5e4+1;
int n,m;
struct EDGE
{
  int fr,to,q;
}e[kMaxM];
int f[kMaxN];
struct EDGE2
{
  int to,nt,qu;
}e2[kMaxN*2];
int hd[kMaxN],cnt;
bool vis[kMaxN];
int deep[kMaxN],st[kMaxN][30],quan[kMaxN][30];
int q;
void Add(int x,int y,int z)
{
  e2[++cnt].to=y;
  e2[cnt].nt=hd[x];
  hd[x]=cnt;
  e2[cnt].qu=z;
}
bool cmp(EDGE x,EDGE y)
{
  return x.q>y.q;
}
int Find(int k)
{
  return f[k]==k?k:f[k]=Find(f[k]);
}
void dfs(int now,int last,int qu)
{
  deep[now]=deep[last]+1;
  st[now][0]=last;
  quan[now][0]=qu;
  for(int i=29;i>=1;i--)//预处理点和权值的st表
  {
    if(deep[now]-(1<<i)>0)
    {
      st[now][i]=st[st[now][i-1]][i-1];
      quan[now][i]=min(quan[now][i-1],quan[st[now][i-1]][i-1]);
    }
  }
  for(int i=hd[now];i;i=e2[i].nt)
  {
    if(!vis[e2[i].to])
    {
      vis[e2[i].to]=true;
      dfs(e2[i].to,now,e2[i].qu);
    }
  }
}
int LCA(int a,int b)//模板
{
  if(deep[a]>deep[b])swap(a,b);
  for(int i=29;i>=0;i--)
  {
    if(deep[b]-(1<<i)>=deep[a])
    {
      b=st[b][i];
    }
  }
  if(a==b)return a;
  for(int i=29;i>=0;i--)
  {
    if(st[a][i]!=st[b][i])
    {
      a=st[a][i],b=st[b][i];
    }
  }
  return st[a][0];
}
int Get(int a,int b)//求从a点到b点最小的边的权值
{
  int ans=INT_MAX;
  for(int i=29;i>=0;i--)//反复跳点
  {
    if(deep[a]-(1<<i)>=deep[b])
    {
      ans=min(ans,quan[a][i]);
      a=st[a][i];
    }
  }
  return ans;
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
  f[i]=i;
  for(int j=0;j<=30;j++)
  {
    quan[i][j]=INT_MAX;
  }
}
for(int i=1;i<=m;i++)
{
  cin>>e[i].fr>>e[i].to>>e[i].q;
}
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++)//求最大生成树
{
  int st=Find(e[i].fr),en=Find(e[i].to);
  if(st==en)continue;
  f[st]=en;
  Add(e[i].fr,e[i].to,e[i].q);
  Add(e[i].to,e[i].fr,e[i].q);
}
for(int i=1;i<=n;i++)//LCA的预处理
{
  if(!vis[i])
  {
    dfs(i,0,INT_MAX);
  }
}
cin>>q;
for(int i=1;i<=q;i++)
{
  int x,y;
  cin>>x>>y;
  if(Find(x)!=Find(y))//不连通
  {
    cout<<"-1\n";
    continue;
  }
  int l=LCA(x,y);//求出LCA
  cout<<min(Get(x,l),Get(y,l))<<"\n";//求x->l和y->l里面最小的边
}
return 0;
}

回复

7 条回复,欢迎继续交流。

正在加载回复...