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

猜你喜欢

转载自www.cnblogs.com/Yuzao/p/9303160.html