亿点问题
查看原帖
亿点问题
647952
JackHu0117楼主2023/4/2 12:42
#include <bits/stdc++.h>//头文件
#define ll long long
#define ull unsigned long long//个人习惯
using namespace std;
const int maxn=500010;//方便一点
const int maxm=300000;
struct edg{//x,y间权值l
	int x,y,l;
}A[maxn];//原图
struct EDG{
	int spot1,spot2,len;
}B[maxn];//建图
int n,m;//城市与道路
int father[maxn];//爸爸(下面那个kruskal并查集里的)
int fa[maxn][30],we[maxn][30],dp[maxn];//爸爸,最大载重(边权)和树深
int head[maxn];
int ans=0x7fffffff;//答案
//lca里要求最小值,所以设大点,0x3f,0x3f3f3f3f,0x3fffffff容易爆
bool vis[maxn];//标记一下,非0即1
int find(int x){//路径压缩
	if(father[x]==x) return x;
	return father[x]=find(father[x]);
}
bool cmp(edg a,edg b){//cmp排序
	return a.l>b.l;
}
int cnt;
void add(int x,int y,int l){//对应原图
	//最大生成树弄出来的图
	B[++cnt].spot1=y;//书上说这叫链式前向星储存
	B[cnt].len=l;
	B[cnt].spot2=head[x];
	head[x]=cnt;
	return;
}
void Kruskal_max(){//求最大生成树
	sort(A+1,A+m+1,cmp);//最大生成树就和最小排序反一下
	for(int i=1;i<=n;i++) father[i]=i;//并查集初始化
	for(int i=1;i<=m;i++){//emm网上的kruskal最大都是1~m或0~m-1耶,为什么和最小生成树不一样呢?
		int ga=find(A[i].x),gb=find(A[i].y);
		if(ga!=gb){
			father[ga]=gb;//请叫我老师板子的搬运工
			add(A[i].x,A[i].y,A[i].l);//开始搬运,原图->建的图
			add(A[i].y,A[i].x,A[i].l);//无向,所以搬两次
		}
	}
	return;//搬完了,拜拜
}
void dfs(int bj){//标记的意思,~~不是拼音党~~,想不到其他变量名了
	vis[bj]=1;//标记
	for(int i=head[bj];i;i=B[i].spot2){//i从邻接表的表头开始每次更新为spot2遍历下一个邻接点
		int st;//起点
		st=B[i].spot1;
		if(vis[st]) continue;//没来过
		fa[st][0]=bj;//存父节点
		we[st][0]=B[i].len;//存到父亲那的权值
		dp[st]=dp[bj]+1;//计算树深
		//有点蒙
		dfs(st);//一轮结束
	}
	return;//快跑
}
void swapp(int &a,int &b){//自制swap函数
	int c;
	c=a;a=b;b=c;//换ab
	return;
}
int LCA_bz(int x,int y){//倍增lca,开始模书上板子
	if(find(x)!=find(y)) return -114514;//不连通的标记
	if(dp[y]>dp[x]) swapp(x,y);//让x置于最底层,使x深度值更大
	for(int i=20;i>=0;i--){
		if(dp[fa[x][i]]>=dp[y]){
			ans=min(ans,we[x][i]);//更新ans(最小边权)
			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(min(we[x][i],we[y][i]),ans);//接着更新ans
            x=fa[x][i];y=fa[y][i];//改x,y的位置 
		}
	}
	ans=min(min(we[x][0],we[y][0]),ans);//梅开三度的更新
	//这时we[x][0],we[y][0]就是公共祖先
	return ans;//答案,你是我的神
}//板子改完哩
int main(){
	cin>>n>>m;//点(城市)和边(道路)
	for(int i=1;i<=m;i++){//m次输入
		cin>>A[i].x>>A[i].y>>A[i].l;//存题目的图
	}
	Kruskal_max();
	for(int i=1;i<=n;i++){//dfs环节
		if(vis[i]==0){
			dp[i]=1;//深度
			dfs(i);
			fa[i][0]=i;
			we[i][0]=0x7fffffff;//要求最小的载重,初始值得大
		}
	}
    for(int i=1;i<=20;i++){//lca初始化,书上
        for(int j=1;j<=n;j++){
            fa[j][i]=fa[fa[j][i-1]][i-1]; 
            we[j][i]=min(we[j][i-1],we[fa[j][i-1]][i-1]);
        }
	}
	int p;
	cin>>p;
	for(int i=1;i<=p;i++){//p次询问
		int x,y;
		cin>>x>>y;
		int as=LCA_bz(y,x);
		ans=0x7fffffff;
		if(as==-114514) cout<<-1<<endl;//lca返回值
		else cout<<as<<endl;
	}
	return 0;//不华丽的结束
}

这段代码Subtask0第一个测试点输出:

6991
28236
6991
6991

但是我下载的数据里正确输出是:

6991
28368
6991
6991

然后我过了?

2023/4/2 12:42
加载中...