【ZJOI2011】最小割

题面

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\n",ans[i]/2);
    puts("");
  }
  return 0;
}

 

posted @ 2019-08-02 17:34  HellPix  阅读(149)  评论(0编辑  收藏  举报