zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    moment.js常用时间示例,时间管理
    RabbitMQ用户增删及权限控制
    CDN概念基本介绍
    在LinkedIn的 Kafka 生态系统
    发行说明
    Kafka 1.0版本发布
    redis应用场景及实例
    Redis哨兵集群
    redis-订阅与发布
    redis事务
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9303160.html
Copyright © 2011-2022 走看看