题面
https://www.luogu.org/problem/P3329
题解
最小割树。
注意最小割树的实现,每次是把当前的$S$和$T$连在一起,权值为$G.dinic()$。
并且每一次建图是重新建全图,不是建区域内的图。
#include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<vector> #include<algorithm> #define ri register int #define N 225 #define M 3050 #define INF 1000000007 using namespace std; inline int read() { int ret=0,f=0; char ch=getchar(); while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0' && ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar(); return f?-ret:ret; } int n,m,cc,sanl,sanr; int u[M],v[M],w[M],val[N]; int id[N],idb[N]; int tid[N]; int dis[N][N]; int qu[40],ans[40]; struct graph { vector<int> ed[N]; vector<int> w,to; int d[N],cur[N]; int S,T; void clean() { w.clear(); to.clear(); for (ri i=0;i<N;i++) ed[i].clear(); } void add_edges(int u,int v,int tw) { to.push_back(v); w.push_back(tw); ed[u].push_back(to.size()-1); to.push_back(u); w.push_back(tw); ed[v].push_back(to.size()-1); } bool bfs() { queue<int> q; memset(d,0x3f,sizeof(d)); d[S]=0; q.push(S); while (!q.empty()) { int x=q.front(); q.pop(); for (ri i=0;i<ed[x].size();i++) { int e=ed[x][i]; if (d[x]+1<d[to[e]] && w[e]) { d[to[e]]=d[x]+1; q.push(to[e]); } } } return d[T]<INF; } int dfs(int x,int limit) { if (x==T || limit==0) return limit; int sum=0; for (ri &i=cur[x];i<ed[x].size();i++) { int e=ed[x][i]; if (w[e] && d[x]+1==d[to[e]]) { int f=dfs(to[e],min(limit,w[e])); if (!f) continue; sum+=f; limit-=f; w[e]-=f; w[1^e]+=f; if (!limit) return sum; } } return sum; } int dinic() { int ret=0; while (bfs()) { memset(cur,0,sizeof(cur)); ret+=dfs(S,INF); } return ret; } } G; struct graph2 { vector<int> to[M],len[M]; void clean() { for (ri i=0;i<M;i++) to[i].clear(); for (ri i=0;i<M;i++) len[i].clear(); } void add_edge(int u,int v,int l) { to[u].push_back(v); len[u].push_back(l); to[v].push_back(u); len[v].push_back(l); } void dfs(int x,int ff,int start,int mi) { if (x<=n) dis[start][x]=mi; for (ri i=0;i<to[x].size();i++) { int y=to[x][i]; if (y==ff) continue; dfs(to[x][i],x,start,min(mi,len[x][i])); } } } G2; void maketree(int l,int r) { if (l>=r) return; G.S=id[l]; G.T=id[r]; for (ri i=1;i<=m;i++) G.w[(i-1)*2]=G.w[(i-1)*2+1]=w[i]; G2.add_edge(G.S,G.T,G.dinic()); int lm=l-1,rm=r+1; for (ri i=l;i<=r;i++) { if (G.d[id[i]]<INF) tid[++lm]=id[i]; else tid[--rm]=id[i]; } for (ri i=l;i<=r;i++) id[i]=tid[i]; maketree(l,lm); maketree(rm,r); } int main() { int T=read(); while (T--) { G.clean();G2.clean(); n=read(); m=read(); for (ri i=1;i<=m;i++) { u[i]=read(); v[i]=read(); w[i]=read(); G.add_edges(u[i],v[i],w[i]); } int q=read(); for (ri i=1;i<=q;i++) qu[i]=read(); for (ri i=1;i<=n;i++) id[i]=i; memset(dis,0,sizeof(dis)); memset(ans,0,sizeof(ans)); memset(val,0,sizeof(val)); maketree(1,n); for (ri i=1;i<=n;i++) G2.dfs(i,i,i,INF); for (ri i=1;i<=n;i++) for (ri j=1;j<=n;j++) if (i!=j) for (ri k=1;k<=q;k++) if (dis[i][j]<=qu[k]) ans[k]++; for (ri i=1;i<=q;i++) printf("%d ",ans[i]/2); puts(""); } return 0; }