CF:Educational Codeforces Round 3 .E.(MST+LCA)
题意:
给定一张带权图,要求对于每一个i,输出包含第i条边的这张图的最小生成树的权值和。
思路:
贪心思路,包含某条边的最小生成树一定是基于最原始的最小生成树得来,考虑对于第i条边,其连接(x,y),求最小生成树中x到y之间的最长边,删去,再加入第i条边。倍增求lca,同时维护区间最大值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m,fa[maxn][30],lg[maxn],dep[maxn],vis[maxn],f[maxn];
ll sum,mcost[maxn][30],ans[maxn];
struct node{
int x,y,z,id;
}p[maxn];
struct NODE{
int y,z;
};
vector<NODE>mp[maxn];
bool cmp(node a,node b){
return a.z<b.z;
}
int find(int x){
if(x==f[x])return x;
return f[x]=find(f[x]);
}
void dfs(int x,int fd,int val){
dep[x]=dep[fd]+1;
mcost[x][0]=val;
fa[x][0]=fd;
for(int i=1;i<=lg[dep[x]];i++){
fa[x][i]=fa[fa[x][i-1]][i-1];
mcost[x][i]=max(mcost[x][i-1],mcost[fa[x][i-1]][i-1]);
}
for(int i=0;i<mp[x].size();i++){
if(mp[x][i].y!=fd)
dfs(mp[x][i].y,x,mp[x][i].z);
}
}
ll lca(int x,int y){
ll res=0;
if(dep[x]<dep[y])swap(x,y);
while(dep[x]!=dep[y]){
int d=lg[dep[x]-dep[y]]-1;
res=max(res,mcost[x][d]);
x=fa[x][d];
}
if(x==y)return res;
for(int i=lg[dep[x]]-1;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
res=max(res,max(mcost[x][i],mcost[y][i]));
x=fa[x][i],y=fa[y][i];
}
}
res=max(res,max(mcost[x][0],mcost[y][0]));
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=n;i++)//预先算出log_2(i)+1的值
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
p[i].id=i;
}
sort(p+1,p+1+m,cmp);
for(int i=1;i<=m;i++){
int fx=find(p[i].x),fy=find(p[i].y);
if(fx!=fy){
f[fx]=fy;
sum+=1ll*p[i].z;
mp[p[i].x].push_back({p[i].y,p[i].z});
mp[p[i].y].push_back({p[i].x,p[i].z});
}
}
dfs(1,0,0);
for(int i=1;i<=m;i++){
ans[p[i].id]=sum-lca(p[i].x,p[i].y)+p[i].z;
}
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
}