1. 程式人生 > >101889I (LCA的另一種實現)

101889I (LCA的另一種實現)

題意:   Q次詢問,每次詢問必須包含特定邊的最小生成樹。

思路: 考慮 最淳樸的最小生成樹,如果加了一條特定邊,肯定是構成了一個環,那麼環外的邊肯定是不變的,要不然,根本就不可能選外面的那些邊了, 所以我們現在就是求這個環上的最小 生成樹,肯定是找樹上之前的 兩個點之間的最大邊,刪掉就行了。

所以問題就變成了,求樹上 任意兩點之間的最大邊。

錯誤思路: 考慮尤拉序列中深度的屬性,想著可不可以求一個最大值。直接把邊權給兒子,詢問的時候直接查詢 最大值就好了。

錯誤樣例1: 找 3 4 之間的最大值,會把 5放進去,就很難受

 

錯誤樣例2:找 1 和 5 的最大值, dfs的時候,可能會很恐怖的先走 1234325,  所以本來不屬於路徑上的點也會被加進來

正確思路: 記錄 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){
	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;
}