bzoj 1937: [Shoi2004]Mst 最小生成树

Description

bzoj 1937: [Shoi2004]Mst 最小生成树

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;
}