Imperial roads Gym - 101889I (LCA的另一种实现)

版权声明:如有错误,请指出,不胜感激。 https://blog.csdn.net/qq_36424540/article/details/82940050

题意:   Q次询问,每次询问必须包含特定边的最小生成树。

思路: 考虑 最淳朴的最小生成树,如果加了一条特定边,肯定是构成了一个环,那么环外的边肯定是不变的,要不然,根本就不可能选外面的那些边了, 所以我们现在就是求这个环上的最小 生成树,肯定是找树上之前的 两个点之间的最大边,删掉就行了。

所以问题就变成了,求树上 任意两点之间的最大边。

错误思路: 考虑欧拉序列中深度的属性,想着可不可以求一个最大值。直接把边权给儿子,询问的时候直接查找 最大值就好了。

错误样例1: 找 3 4 之间的最大值,会把 5放进去,就很难受

 

错误样例2:找 1 和 5 的最大值, dfs的时候,可能会很恐怖的先走 1234325,  所以本来不属于路径上的点也会被加进来

扫描二维码关注公众号,回复: 3464837 查看本文章

正确思路: 记录 fa[i][j]  //表示 i 的上面距离为 2^{j} 的祖先是谁

           同样记录 dis[i][j] //表示 i 的上面距离为2^{j} 范围内的最大边权

然后就是LCA的跳跃了

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=b-1;i>=a;--i)

map<pair<int,int>,int> id;
const int N=1e5+10;

int has[N*2];

struct Edge{
	int u,v,w,nt;
	Edge(int _u=0,int _v=0,int _w=0,int _nt=0){
		u=_u,v=_v,w=_w,nt=_nt;
	}
}edge[N*4],e[N*4];
int head[N],cnt;
void add_edge(int u,int v,int w){
	edge[cnt]=Edge(u,v,w,head[u]);
	head[u]=cnt++;
}

int cmp(Edge a,Edge b){
	return a.w<b.w;
}


int pre[N];
int find_rt(int x){
	return pre[x]==x?x:pre[x]=find_rt(pre[x]);
}
int join(int u,int v){
	int ru=find_rt(u),rv=find_rt(v);
	if(ru!=rv){
		pre[ru]=rv;
		return 1;
	}
	return 0;
}


int dep[N];
int fa[N][20],dis[N][20];
void dfs(int u,int f,int w){
	fa[u][0]=f;
	dis[u][0]=w;

	dep[u]=dep[f]+1;
	for(int i=head[u];i!=-1;i=edge[i].nt){
		Edge& e=edge[i];
		if(e.v==f)continue;
		dfs(e.v,u,e.w);
	}
}
int Log[N],mx_h;
void QQQ(int n){
	for(int j=1;(1<<j)<=n;j++){
		for(int i=1;i<=n;i++){
			int t=fa[i][j-1];
			fa[i][j]=fa[t][j-1];
			dis[i][j]=max(dis[i][j-1],dis[t][j-1]);
		}
	}
	mx_h=Log[n];
}
//!!!特别注意次序,那个x,y一定要在最后才跳跃
int swim(int& x,int d){
	int res=0;
	for(int i=0;i<=mx_h;i++){
		if(d&(1<<i)){
			res=max(res,dis[x][i]);
			x=fa[x][i];
		}
	}
	return res;
}
int LCA(int x,int y){
        //!!! 一定要先比较深度,把浅的放在x上
	if(dep[x]>dep[y])swap(x,y);
	int ans=swim(y,dep[y]-dep[x]);
	if(x==y)return ans;//如果x 就是Y的祖先,那么久结束了
	for(int i=mx_h;i>=0;i--){
		if(fa[x][i]!=fa[y][i]){
			ans=max(ans,dis[x][i]);
			ans=max(ans,dis[y][i]);
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	//printf("x:%d y:%d\n",x,y);
	ans=max(ans,dis[x][0]);
	ans=max(ans,dis[y][0]);
	return ans;
}


int main(){
	Log[1]=0;
	rep(i,2,N)Log[i]=Log[i/2]+1;

	int n,m;
	scanf("%d %d",&n,&m);

	cnt=0;
	rep(i,0,n+1){
		head[i]=-1;
		pre[i]=i;
	}

	rep(i,0,m){
		int u,v,w;
		scanf("%d %d %d",&u,&v,&w);
		e[i]=Edge(u,v,w);
	}

	sort(e,e+m,cmp);
	rep(i,0,m)id[make_pair(e[i].u,e[i].v)]=i;

	int sum=0;
	rep(i,0,m){
		Edge& ee=e[i];
		if(join(ee.v,ee.u)){
			sum+=ee.w;
			has[i]=1;
			add_edge(ee.u,ee.v,ee.w);
			add_edge(ee.v,ee.u,ee.w);
		}
	}

	dfs(1,0,0);
	QQQ(n);

	int q;
	scanf("%d",&q);
	rep(i,0,q){
		int u,v;
		scanf("%d %d",&u,&v);
		int dd=id[make_pair(u,v)];
		if(has[dd]){
			printf("%d\n",sum);
			continue;
		}
		int w=LCA(u,v);
		printf("%d\n",sum-w+e[dd].w);
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36424540/article/details/82940050