社区讨论

极其离谱(最大生成树 倍增 55分)

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

讨论操作

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

当前回复
3 条
当前快照
1 份
快照标识符
@lo8trw6f
此快照首次捕获于
2023/10/28 00:26
2 年前
此快照最后确认于
2023/10/28 00:26
2 年前
查看原帖
首先只有55pts
然后更离谱的是,ggf数组范围是5e5+10和1e6+10的时候错的点还不一样(但甚至都是55pts
求大佬帮忙看看 /kk
CPP
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,edn,tot,tut,q;
const int maxn=5e5+10;
const int maxm=1e6+10;
struct edge{
	int x,y,v;
}g[maxm];
struct node{
	int to,w,nxt;
	node() {nxt=-1;}
}gf[maxm];
int fa[maxn], head[maxn], logs[50], depth[maxn], fath[maxn][50];
int vis[maxn], dis[maxn][50];
void logo(){
	logs[1]=0;
	logs[2]=1;
	for(int i=3; i<maxn; i++) {
		logs[i]=logs[i/2]+1;
	}
}
int find(int x){
	while(x!=fa[x])
		x=fa[x]=fa[fa[x]];
	return x;
}
void addEdge(int x, int y, int w) {
	gf[++tot].to=y;
	gf[tot].w=w;
	gf[tot].nxt=head[x];
	head[x]=tot;
}
void kruskal() {
	sort(g+1,g+edn+1,[&](const edge& a, const edge& b) {return a.v > b.v; });
	for(int i=1; i<=edn; i++) {
		int uex=find(g[i].x), uey=find(g[i].y);
		if(uex==uey) continue;
		addEdge(g[i].x, g[i].y, g[i].v);
		addEdge(g[i].y, g[i].x, g[i].v);
		fa[uex]=uey;
		if(++tut==n) break;
	}
}
void dfs(int now, int last, int v) {
	vis[now]=1;
	dis[now][0]=v;
	depth[now]=depth[last]+1;
	fath[now][0]=last;
	for(int i=1;i<=logs[depth[now]];i++) {
		fath[now][i]=fath[fath[now][i-1]][i-1];
		dis[now][i]=min(dis[now][i-1], dis[fath[now][i-1]][i-1]);
	}
	
	for(int i=head[now]; ~i; i=gf[i].nxt) {
		if(gf[i].to!=last) dfs(gf[i].to, now, gf[i].w);
	}
}
int lca(int x, int y) {
	if(find(x)!=find(y)) return -1;
	int ans=0x7fffffff;
	// 求路径上最短边权
	if(depth[x] < depth[y]) swap(x, y);
	while(depth[x] > depth[y]) {
		ans=min(ans, dis[x][logs[depth[x]-depth[y]-1]]);
		x=fath[x][logs[depth[x]-depth[y]-1]];
	}
	if(x==y) return ans;
	for(int k=logs[depth[x]]-1; k>=0; k--)
		if(fath[x][k]!=fath[y][k]) {
			ans=min(ans, dis[x][k]);
			ans=min(ans, dis[y][k]);
			x=fath[x][k],y=fath[y][k];
		}
	ans=min(ans, min(dis[x][0], dis[y][0]));
	return ans;
}
int main() {
	logo();
	scanf("%d %d", &n, &m);
	for(int i=1;i<=m;i++) {
		int x,y,z;
		scanf("%d %d %d", &x, &y, &z);
		g[++edn].x=x;
		g[edn].y=y;
		g[edn].v=z;
	}
	scanf("%d", &q);
	for(int i=1;i<=n;i++) {
		fa[i]=i;
		head[i]=-1;
	}
	kruskal();
	for(int i=1;i<=n;i++) if(!vis[i]) dfs(i, 0, 0); 

	while(q--) {
		int x,y;
		scanf("%d %d", &x, &y);
		printf("%d\n", lca(x,y));
	}
	return 0;
}

回复

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

正在加载回复...