CF609E Minimum spanning tree for each edge
作者:互联网
先求出最小生成树。
加入一条边后肯定会形成环,我们需要找环上的非添加边的最大边,断掉。
也就是说,对于 \((u,v)\),找出 MST 里 \(u,v\) 间最大边权。
典型的边权树剖。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+5;
int n,m;
struct edge{
int u,v,w,id;
bool isin;
bool operator <(const edge &b)const{return w<b.w;}
}Edge[maxn];
int Fa[maxn];
int Find(int x){
return Fa[x]==x?x:Fa[x]=Find(Fa[x]);
}
int res=0;
vector<int> e[maxn];
int dep[maxn],fa[maxn],sze[maxn],son[maxn],to[maxn],seg[maxn],rev[maxn];
int a[maxn];
int xds[maxn<<2];
#define ls (k<<1)
#define rs (k<<1|1)
#define mid (l+r>>1)
void pushup(int k){
xds[k]=max(xds[ls],xds[rs]);
}
void build(int k,int l,int r){
if(l==r){
xds[k]=a[rev[l]];
return ;
}
build(ls,l,mid);build(rs,mid+1,r);
pushup(k);
}
int query(int k,int l,int r,int x,int y){
if(x<=l&&r<=y)return xds[k];
int res=0;
if(x<=mid)res=max(res,query(ls,l,mid,x,y));
if(mid<y)res=max(res,query(rs,mid+1,r,x,y));
return res;
}
void dfs1(int u,int f){
fa[u]=f,dep[u]=dep[f]+1,sze[u]=1;
for(auto v:e[u]){
if(v!=f){
dfs1(v,u);
sze[u]+=sze[v];
if(sze[v]>sze[son[u]])son[u]=v;
}
}
}
void dfs2(int u,int t){
seg[u]=++seg[0],rev[seg[0]]=u,to[u]=t;
if(!son[u])return ;
dfs2(son[u],t);
for(auto v:e[u]){
if(v!=fa[u]&&v!=son[u])dfs2(v,v);
}
}
int treequery(int x,int y){
int res=-0x3f3f3f3f;
while(to[x]!=to[y]){
if(dep[to[x]]<dep[to[y]])swap(x,y);
res=max(res,query(1,1,n,seg[to[x]],seg[x]));
x=fa[to[x]];
}
if(dep[x]>dep[y])swap(x,y);
res=max(res,query(1,1,n,seg[x]+1,seg[y]));
return res;
}
int ans[maxn];
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++)Fa[i]=i;
for(int i=1;i<=m;i++)cin>>Edge[i].u>>Edge[i].v>>Edge[i].w,Edge[i].isin=0,Edge[i].id=i;
sort(Edge+1,Edge+m+1);
for(int i=1;i<=m;i++){
int u=Edge[i].u,v=Edge[i].v,w=Edge[i].w;
if(Find(u)==Find(v))continue;
Fa[Find(u)]=Find(v);
e[u].push_back(v);
Edge[i].isin=1;
e[v].push_back(u);
res+=w;
}
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=m;i++){
if(Edge[i].isin){
int u=Edge[i].u,v=Edge[i].v,w=Edge[i].w;
if(dep[u]<dep[v])a[v]=w;
else a[u]=w;
}
}
build(1,1,n);
for(int i=1;i<=m;i++){
if(Edge[i].isin)ans[Edge[i].id]=res;//实际上珂以不要
else{
int u=Edge[i].u,v=Edge[i].v,w=Edge[i].w;
ans[Edge[i].id]=res+w-treequery(u,v);
}
}
for(int i=1;i<=m;i++)cout<<ans[i]<<endl;
return 0;
}
标签:int,tree,CF609E,son,seg,Minimum,Edge,maxn,xds 来源: https://www.cnblogs.com/kkksc0100/p/no-using_shengchenghanshu.html