p4126 [AHOI2009]最小割

传送门

分析

我们先跑一遍最小割

然后我们只留下没满流的边进行tarjan

如果一条边连两点不在一个联通块里则一定在一个方案里

如果起点和s在一个联通块中且终点和t在一个联通块中,那它一定是一个关键边

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int inf = 1e9+7;
int n,m,s,t,level[5010],head[5010],cnt,to[120100],nxt[120100],w[120100],fm[120100];
int cur[5010],ano[120100],dfn[5010],belong[5010],low[5010],ist[5010],sum,tot;
stack<int>a;
inline void add(int x,int y,int z){
    nxt[++cnt]=head[x];
    head[x]=cnt;
    to[cnt]=y;
    w[cnt]=z;
    fm[cnt]=x;
    nxt[++cnt]=head[y];
    head[y]=cnt;
    to[cnt]=x;
    w[cnt]=0;
    fm[cnt]=y;
    ano[cnt-1]=cnt;
    ano[cnt]=cnt-1;
}
inline bool bfs(){
    memset(level,-1,sizeof(level));
    queue<int>q;
    int i,j,k;
    q.push(s);
    level[s]=0;
    while(!q.empty()){
      int x=q.front();
      q.pop();
      for(i=head[x];i;i=nxt[i])
        if(w[i]&&level[to[i]]==-1){
          level[to[i]]=level[x]+1;
          if(to[i]==t)return 1;
          q.push(to[i]);
        }
    }
    return 0;
}
inline int dfs(int x,int flow){
    if(x==t||!flow)return flow;
    int res=0,i,j,k;
    cur[x]=head[x];
    for(i=cur[x];i;i=nxt[i]){
      cur[x]=i;
      if(w[i]&&level[to[i]]==level[x]+1){
        int f=dfs(to[i],min(flow-res,w[i]));
        w[i]-=f;
        w[ano[i]]+=f;
        res+=f;
      }
    }
    if(!res)level[x]=-1;
    return res;
}
inline void tarjan(int x){
    dfn[x]=low[x]=++tot;
    a.push(x);
    ist[x]=1;
    for(int i=head[x];i;i=nxt[i]){
      if(!w[i])continue;
      if(!dfn[to[i]]){
          tarjan(to[i]);
          low[x]=min(low[x],low[to[i]]);
      }else if(ist[to[i]]){
          low[x]=min(low[x],dfn[to[i]]);
      }
    }
    if(low[x]==dfn[x]){
      sum++;
      while(1){
          int u=a.top();
          a.pop();
          ist[u]=0;
          belong[u]=sum;
          if(u==x)break;
      }
    }
}
int main(){
    int i,j,k;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(i=1;i<=m;i++){
      int x,y,z;
      scanf("%d%d%d",&x,&y,&z);
      add(x,y,z);
    }
    while(bfs())while(int a=dfs(s,inf));
    for(i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    for(i=1;i<=cnt;i+=2){
      if(w[i])puts("0 0");
        else {
          if(belong[to[i]]!=belong[fm[i]])printf("1 ");
            else printf("0 ");
          if(belong[to[i]]==belong[t]&&belong[fm[i]]==belong[s])puts("1");
            else puts("0");
        }
    }
    return 0;
}
posted @ 2019-03-27 10:28  水题收割者  阅读(200)  评论(0编辑  收藏  举报