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;
    }
    
    
  • 相关阅读:
    HDOJ 1846 Brave Game
    并查集模板
    HDU 2102 A计划
    POJ 1426 Find The Multiple
    POJ 3278 Catch That Cow
    POJ 1321 棋盘问题
    CF 999 C.Alphabetic Removals
    CF 999 B. Reversing Encryption
    string的基础用法
    51nod 1267 4个数和为0
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9303160.html
Copyright © 2011-2022 走看看