社区讨论
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 条回复,欢迎继续交流。
正在加载回复...