题意:
给一个生成树,求最少要更改多少边权,使得这个生成树是最小生成树。
题解:
容易得到,树边只减,非数边只加,不然不忧。
先将给的生成树建出来,那么对于非树边,它的权值最终一定大于等于它连的两点在树上的路径的任意一边。
假设有树边i,非树边j。且i,j在一个环上,有
w[i]−di<=w[j]+dj
得到
w[i]−w[j]<=di+dj
那么将
w[i]−w[j]
看作边权,
di,dj
看作KM中的顶标,KM算法有这样一个性质:最大权匹配时顶标和最小(相等子图扩到最大),所以跑KM/最大费用流就可以了。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
struct node{
int x,y,c,d,next,other;
}e[810],a[2000000];int len=0,last[810];
int st,ed;
int n,m;
int map[55][55],fa[55][20],dep[55];
bool check[55][55];
int s[810],p[810],q[810];
bool u[810];
void ins(int x,int y,int c,int d)
{
int k1=++len;
a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
a[len].next=last[x];last[x]=len;
int k2=++len;
a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
a[len].next=last[y];last[y]=len;
a[k1].other=k2;
a[k2].other=k1;
}
bool spfa()
{
memset(s,-63,sizeof(s));
memset(u,false,sizeof(u));
int l=1,r=2;q[l]=st;s[st]=0;u[st]=true;
while(l!=r)
{
int x=q[l];
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(s[y]<s[x]+a[i].d&&a[i].c>0)
{
s[y]=s[x]+a[i].d;
p[y]=i;
if(!u[y])
{
u[y]=true;
q[r]=y;
r++;if(r>ed+1) r=1;
}
}
}
u[x]=false;
l++;if(l>ed+1) l=1;
}
return s[ed]>0;
}
int flow()
{
int x=ed;
int ans=0,min=-1;
while(x!=st)
{
int i=p[x];
if (a[i].c<min||min==-1)min=a[i].c;
x=a[i].x;
}
x=ed;
while(x!=st)
{
int i=p[x];
a[i].c-=min;
a[a[i].other].c+=min;
x=a[i].x;
ans=ans+a[i].d*min;
}
return ans;
}
void dfs(int x,int f)
{
fa[x][0]=f;dep[x]=dep[f]+1;
for(int i=1;(1<<i)<=dep[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=1;i<=n;i++)
if(i!=f&&check[x][i]) dfs(i,x);
}
int solve(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=10;i>=0;i--)
if((1<<i)<=dep[x]-dep[y]) x=fa[x][i];
if(x==y) return x;
for(int i=10;i>=0;i--)
if((1<<i)<=dep[x]&&fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main()
{
scanf("%d %d",&n,&m);
memset(check,false,sizeof(check));
for(int i=1;i<=m;i++) scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].c),map[e[i].x][e[i].y]=map[e[i].y][e[i].x]=i;
for(int i=1;i<n;i++)
{
int x,y;scanf("%d %d",&x,&y);
check[x][y]=check[y][x]=true;
}
dep[0]=-1;dfs(1,0);
st=0;ed=m+1;
for(int i=1;i<=m;i++)
{
int x=e[i].x,y=e[i].y;
if(check[x][y]) ins(st,i,1,0);
else
{
ins(i,ed,1,0);
int lca=solve(x,y);
while(x!=lca)
{
int t=map[x][fa[x][0]];
ins(t,i,1,e[t].c-e[i].c);
x=fa[x][0];
}
while(y!=lca)
{
int t=map[y][fa[y][0]];
ins(t,i,1,e[t].c-e[i].c);
y=fa[y][0];
}
}
}
int ans=0;
while(spfa()) ans+=flow();
printf("%d",ans);
}