luoguP4897 【模板】最小割树(Gomory-Hu Tree)
吸氧才能过,写一个分治就行.
这里讲一下构造方法:考虑对点集 $U$ 求最小割树.
随便选取两个点 $u,v$ 然后跑一个 $u$ 到 $v$ 的最小割.
然后有两条性质:
- 对于 $U$ 中的每个点,一定被划分到了 $u$ 集合或 $v$ 集合(废话)
- 对于 $u$ 集合点到 $v$ 集合点的最小割一定小于等于 $u$ 到 $v$ 的最小割(最坏情况也可以取到 $u$ 到 $v$ 的最小割)
然后这么递归,一共跑 $n-1$ 次最大流,查询的时候查询树上路径最小边权就行了.
code:
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#define N 503
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
namespace net
{
#define inf 1000000000
struct Edge
{
int u,v,c;
Edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){}
};
queue<int>q;
vector<Edge>edges;
vector<int>G[N];
int vv[N],vis[N],d[N],col[N],s,t;
void add(int u,int v,int c)
{
edges.push_back(Edge(u,v,c));
edges.push_back(Edge(v,u,0));
int o=edges.size();
G[u].push_back(o-2);
G[v].push_back(o-1);
}
int dfs(int x,int cur)
{
if(x==t)
return cur;
int an=0,flow=0;
for(int i=vv[x];i<G[x].size();++i,++vv[x])
{
Edge e=edges[G[x][i]];
if(e.c>0&&d[e.v]==d[x]+1)
{
an=dfs(e.v,min(cur,e.c));
if(an)
{
cur-=an;
flow+=an;
edges[G[x][i]].c-=an;
edges[G[x][i]^1].c+=an;
if(!cur)
break;
}
}
}
return flow;
}
int bfs()
{
memset(vis,0,sizeof(vis));
d[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<G[u].size();++i)
{
if(edges[G[u][i]].c>0)
{
int v=edges[G[u][i]].v;
if(!vis[v])
{
vis[v]=1;
d[v]=d[u]+1;
q.push(v);
}
}
}
}
return vis[t];
}
int maxflow()
{
int re=0;
while(bfs())
{
memset(vv,0,sizeof(vv));
re+=dfs(s,inf);
}
return re;
}
void emp()
{
memset(vv,0,sizeof(vv));
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(d));
for(int i=0;i<edges.size();i+=2)
{
edges[i].c+=edges[i^1].c;
edges[i^1].c=0;
}
}
void mark(int x,int co)
{
if(col[x]==co)
return;
col[x]=co;
for(int i=0;i<G[x].size();++i)
{
Edge e=edges[G[x][i]];
if(e.c>0)
mark(e.v,co);
}
}
};
int n,m,edges,id,dep[N];
int minn[15][N],fa[15][N];
int tmp1[N],tmp2[N],a[N],hd[N],to[N<<1],nex[N<<1],val[N<<1];
void add(int u,int v,int c)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void solve(int l,int r)
{
if(l>=r)
return;
++id;
net::emp();
net::s=a[l];
net::t=a[l+1];
int cur=net::maxflow();
add(a[l],a[l+1],cur);
add(a[l+1],a[l],cur);
net::mark(a[l],id);
int t1=0,t2=0;
for(int i=l;i<=r;++i)
if(net::col[a[i]]==id)
tmp1[++t1]=a[i];
else
tmp2[++t2]=a[i];
int L=l,R=r;
for(int i=1;i<=t1;++i)
a[L++]=tmp1[i];
for(int i=1;i<=t2;++i)
a[L++]=tmp2[i];
solve(l,l+t1-1);
solve(r-t2+1,r);
}
void dfs(int x,int ff)
{
dep[x]=dep[ff]+1;
for(int i=1;i<15;++i)
{
fa[i][x]=fa[i-1][fa[i-1][x]];
minn[i][x]=min(minn[i-1][x],minn[i-1][fa[i-1][x]]);
}
for(int i=hd[x];i;i=nex[i])
{
int y=to[i];
if(y==ff)
continue;
fa[0][y]=x;
minn[0][y]=val[i];
dfs(y,x);
}
}
int query(int x,int y)
{
if(dep[x]>dep[y])
swap(x,y);
int re=inf;
if(dep[x]!=dep[y])
{
for(int i=14;i>=0;--i)
if(dep[fa[i][y]]>=dep[x])
re=min(re,minn[i][y]),y=fa[i][y];
}
if(x==y)
return re;
for(int i=14;i>=0;--i)
{
if(fa[i][x]!=fa[i][y])
{
re=min(re,minn[i][x]);
re=min(re,minn[i][y]);
x=fa[i][x];
y=fa[i][y];
}
}
re=min(re,minn[0][x]);
re=min(re,minn[0][y]);
return re;
}
int main()
{
// setIO("input");
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
net::add(u,v,w);
net::add(v,u,w);
}
for(int i=1;i<=n;++i)
a[i]=i;
memset(minn,0x3f,sizeof(minn));
solve(1,n),dfs(1,0);
int Q;
scanf("%d",&Q);
for(int i=1;i<=Q;++i)
{
int x,y,ans;
scanf("%d%d",&x,&y);
ans=query(x,y);
printf("%d\n",ans>=inf?-1:ans);
}
return 0;
}

浙公网安备 33010602011771号