题意: Q次询问,每次询问必须包含特定边的最小生成树。
思路: 考虑 最淳朴的最小生成树,如果加了一条特定边,肯定是构成了一个环,那么环外的边肯定是不变的,要不然,根本就不可能选外面的那些边了, 所以我们现在就是求这个环上的最小 生成树,肯定是找树上之前的 两个点之间的最大边,删掉就行了。
所以问题就变成了,求树上 任意两点之间的最大边。
错误思路: 考虑欧拉序列中深度的属性,想着可不可以求一个最大值。直接把边权给儿子,询问的时候直接查找 最大值就好了。
错误样例1: 找 3 4 之间的最大值,会把 5放进去,就很难受
错误样例2:找 1 和 5 的最大值, dfs的时候,可能会很恐怖的先走 1234325, 所以本来不属于路径上的点也会被加进来
正确思路: 记录 fa[i][j] //表示 的上面距离为
的祖先是谁
同样记录 dis[i][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;
}