版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/82957120
题目链接:https://odzkskevi.qnssl.com/fa6682426fb11e87a5ab9246f22a461d?v=1538477779
题意:
给你n点m边的图,给你q个询问,每个询问都有一个a和b,要你输出保留点a和点b这条边后的最小生成树的权值。
做法:
用倍增的方法保存一个maxx[i][j]表示点i向上走(1<<j)步后的最大值,在求两点的LCA的过程中找到最大值,然后将原来的最小生成树减去这个最大值加上两边对应的权值即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=400005;
const int maxm=400005;
int dist[maxn],fa[maxn][30],n,m,q,head[maxn],now,vis[maxn];
int dep[maxn],ff[maxn],maxx[maxn][30],qu[maxn],qv[maxn],qw[maxn];
struct edge{
int u,v,val;
bool operator < (const edge &a) const {
if(u!=a.u) return u<a.u;
return v<a.v;
}
}ed[maxm*2];
map<edge,int> mp;
bool cmp(edge a,edge b){
return a.val<b.val;
}
struct node{
int to,from,next,val;
}e[maxm<<1];
void dfs(int now,int f){
vis[now]=1;
for(int i=head[now];~i;i=e[i].next){
int u=e[i].to;
if(u==f) continue;
dep[u]=dep[now]+1;
fa[u][0]=now;
maxx[u][0]=e[i].val;
if(!vis[u]){
dfs(u,now);
}
}
}
int fin(int x){
return ff[x]==x?x:ff[x]=fin(ff[x]);
}
void add(int u,int v,int w){
e[now].to=v,e[now].from=u,e[now].val=w;
e[now].next=head[u],head[u]=now++;
}
void deal(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++){
fa[i][j]=fa[fa[i][j-1]][j-1];
maxx[i][j]=max(maxx[i][j],maxx[fa[i][j-1]][j-1]);
}
}
int LCA(int x,int y){
int ans=0,pos;
if(dep[x]<dep[y]) swap(x,y);
for(pos=0;(1<<pos)<=dep[x];pos++);
pos--;
for(int i=pos;i>=0;i--)
if(dep[x]-(1<<i)>=dep[y]){
ans=max(ans,maxx[x][i]);
x=fa[x][i];
}
if(x==y) return ans;
for(int i=pos;i>=0;i--)
if(fa[x][i]!=fa[y][i]&&fa[x][i]!=-1){
ans=max(ans,maxx[x][i]);
ans=max(ans,maxx[y][i]);
x=fa[x][i],y=fa[y][i];
}
ans=max(ans,maxx[x][0]);
ans=max(ans,maxx[y][0]);
return ans;
}
void init(){
memset(fa,-1,sizeof(fa));
}
int main(){
int x,y,z;
mp.clear();
init();
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)
ff[i]=i,head[i]=-1;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].val);
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d%d",&qu[i],&qv[i]);
mp[edge{qu[i],qv[i],0}]=i;
mp[edge{qv[i],qu[i],0}]=i;
}
for(int i=1;i<=m;i++){
int t=mp[edge{ed[i].u,ed[i].v,0}];
if(t!=0) qw[t]=ed[i].val;
}
sort(ed+1,ed+1+m,cmp);
int sum=0,num=0;
for(int i=1;i<=m&&num<n-1;i++){
int u=fin(ed[i].u),v=fin(ed[i].v);
if(u!=v){
num++;
ff[u]=v;
sum+=ed[i].val;
add(ed[i].u,ed[i].v,ed[i].val);
add(ed[i].v,ed[i].u,ed[i].val);
}
}
dep[1]=1;
fa[1][0]=1;
dfs(1,-1);
deal();
for(int i=1;i<=q;i++){
int aim=LCA(qu[i],qv[i]);
printf("%d\n",sum+qw[i]-aim);
}
return 0;
}