bzoj 1937: [Shoi2004]Mst 最小生成树
Description
Solution
对于一条非 \(T\) 边 \((x,y)\), 它最后要比所有 \(T\) 中 \((x,y)\) 路径上的边的权值要大.
我们设增量为 \(d[i]\) , 对于树边 \(i\) , 和穿过它的任意非树边 \(j\) ,满足 \(w[i]-d[i]<=w[j]+d[j]\)
移项 : \(w[i]-w[j]<=d[i]+d[j]\) , 也就是 \(d[i]+d[j]\) 的和尽量要小 , 这就对应 \(KM\) 中顶标的要求 , 把 \(w[i]-w[j]\) 设为边权对树边和对应非树边跑个最大权匹配就行了.
#include<bits/stdc++.h>
using namespace std;
template<class T>void gi(T &x){
int f;char c;
for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=1605;
struct edge{int x,y,z,f;}e[N];
int head[N],nxt[N],to[N],num=1,id[N],n,m,dep[N],fa[N][13],sf[N];
map<int,int>Map[55];
int a[N/2][N/2],c[N/2],d[N],ids=0,A,B,w[N],v[N],tim=0,b[N],vl[N],vr[N],dis[N];
inline void link(int x,int y,int z,int di){
nxt[++num]=head[x],to[num]=y,head[x]=num,id[num]=z,dis[num]=di;
nxt[++num]=head[y],to[num]=x,head[y]=num,id[num]=z,dis[num]=di;
}
inline void bfs(int x,int la){
for(int i=1;i<=12;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x],u;i;i=nxt[i]){
if((u=to[i])==la)continue;
dep[u]=dep[x]+1,fa[u][0]=x,e[Map[x][u]].f=1,sf[u]=i,bfs(u,x);
}
}
inline int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=12;i>=0;i--)if((dep[x]-dep[y])>>i&1)x=fa[x][i];
if(x==y)return x;
for(int i=12;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
inline void solve(int x,int y,int z,int W){
while(x!=y){
a[id[sf[x]]][z]=max(0,dis[sf[x]]-W);
x=to[sf[x]^1];
}
}
inline bool dfs(int x){
vl[x]=tim;
for(int i=1;i<=B;i++){
if(vr[i]==tim)continue;
int d=w[x]+v[i]-a[x][i];
if(d==0){
vr[i]=tim;
if(!b[i]||dfs(b[i]))return b[i]=x,1;
}
else c[i]=min(c[i],d);
}
return 0;
}
inline void KM(){
for(int i=1;i<=A;i++)
for(int j=1;j<=B;j++)w[i]=max(w[i],a[i][j]);
for(int i=1;i<=A;i++){
memset(c,127,sizeof(c));
++tim;
if(dfs(i))continue;
while(1){
int d=1<<30,y=0;
for(int i=1;i<=B;i++)if(vr[i]!=tim)d=min(d,c[i]);
for(int i=1;i<=A;i++)if(vl[i]==tim)w[i]-=d;
for(int i=1;i<=B;i++)
if(vr[i]==tim)v[i]+=d;
else if(!(c[i]-=d))y=i;
if(!b[y])break;
int x=b[y];vl[x]=vr[y]=tim;
for(int i=1;i<=B;i++)c[i]=min(c[i],w[x]+v[i]-a[x][i]);
}
++tim,dfs(i);
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n>>m;
int x,y,z,ans=0;
for(int i=1;i<=m;i++){
gi(x),gi(y),gi(z);
e[i]=(edge){x,y,z,0},Map[x][y]=Map[y][x]=i;
}
for(int i=2;i<=n;i++)
gi(x),gi(y),link(x,y,++ids,e[Map[x][y]].z),e[Map[x][y]].f=1;
A=n-1,B=m-n+1,bfs(1,1);
for(int i=1,z,t=0;i<=m;i++){
if(e[i].f)continue;
x=e[i].x,y=e[i].y,z=lca(x,y);
solve(x,z,++t,e[i].z),solve(y,z,t,e[i].z);
}
KM();
for(int i=max(A,B);i;i--)ans+=w[i]+v[i];
cout<<ans;
return 0;
}