给一幅无权无向无环图并给出它的一颗生成树,要求出一个最小割,并且最小割中有且仅有一条树边。
一条从u到v的非树边会让它从树上u到v路径上的边成为最小割的代价+1,所以考虑树链剖分把所有非树边作为更新来更新路径上边的代价。
因为只需要在最后找出最小的那条边,所以直接差分即可。
#include <bits/stdc++.h> #define pb push_back #define mp make_pair #define fi first #define se second #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define up rt,rt<<1,rt<<1|1 #define mem(x) memset(x,0,sizeof(x)) #define mem1(x) memset(x,-1,sizeof(x)) #define LMissher using namespace std; typedef long long ll; typedef double db; const int M = 1e5+7; const double pi = acos(-1); const int inf = 2147483647; const int mod = 1e9+7; int _,n,m,cas=1; int cnt,head[M],tot; int sz[M],son[M],f[M],dep[M],rnk[M],id[M],top[M],sum[M]; struct edge { int v,nex; }e[M<<1]; void init(){ tot=cnt=0;mem1(head);mem(sum); } void add(int u,int v){ e[++cnt].v=v;e[cnt].nex=head[u]; head[u]=cnt; } void dfs(int u,int fa,int d){ sz[u]=1,f[u]=fa,dep[u]=d,son[u]=-1; for(int i=head[u];~i;i=e[i].nex){ int v=e[i].v; if(v==fa) continue; dfs(v,u,d+1); sz[u]+=sz[v]; if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v; } return ; } void dfs1(int u,int t){ id[u]=++tot; rnk[tot]=u; top[u]=t; if(son[u]!=-1) dfs1(son[u],t); for(int i=head[u];~i;i=e[i].nex){ int v=e[i].v; if(v==f[u]||v==son[u]) continue; dfs1(v,v); } return ; } void update(int x,int y){ int fx=top[x],fy=top[y]; while(fx!=fy){ if(dep[fx]>dep[fy]){ sum[id[fx]]++;sum[id[x]+1]--; x=f[fx],fx=top[x]; } else{ sum[id[fy]]++;sum[id[y]+1]--; y=f[fy],fy=top[y]; } } if(dep[x]>dep[y]){ sum[id[son[y]]]++;sum[id[x]+1]--; } else{ sum[id[son[x]]]++;sum[id[y]+1]--; } } int main(){ #ifdef LMissher freopen("1.in","r",stdin); freopen("1.out","w",stdout); #endif scanf("%d",&_); while(_--){ init(); scanf("%d%d",&n,&m); int i=1; for(;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v);add(v,u); } dfs(1,-1,1); dfs1(1,1); for(;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); update(u,v); } int ans=inf; for(int i=2;i<=n;i++) sum[i]+=sum[i-1],ans=min(ans,sum[i]); printf("Case #%d: %d\n",cas++,ans+1); } return 0; }