BZOJ 4519 [Cqoi2016]不同的最小割 最小割树(分治最小割)

来源:互联网 发布:ipad的蜂窝移动数据 编辑:程序博客网 时间:2024/04/30 11:46
#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#define N 1005#define INF 1000000000using namespace std;int n,m,seq[N],w[N*10];namespace NetworkFlow {    struct Edge {        int from,to,nxt,cap;        Edge() {}        Edge(int _from,int _to,int _nxt,int _cap):            from(_from),to(_to),nxt(_nxt),cap(_cap) {}    }e[N*20];    int tot,S,T,fir[N],cur[N],d[N];    void Add_Edge(int from,int to,int cap) {        e[++tot]=Edge(from,to,fir[from],cap), fir[from]=tot;        e[++tot]=Edge(to,from,fir[to],0), fir[to]=tot;        return ;    }    bool bfs() {        queue<int> q;        for(int i=1;i<=n;++i) d[i]=-1;        d[S]=0, q.push(S);        while(!q.empty()) {            int x=q.front(); q.pop();            for(int i=fir[x];~i;i=e[i].nxt) {                if(!e[i].cap || d[e[i].to]!=-1) continue;                d[e[i].to]=d[x]+1;                if(e[i].to==T) return true;                q.push(e[i].to);            }        }        return false;    }    int dfs(int x,int now) {        if(!now || x==T) return now;        int f,flow=0;        for(int& i=cur[x];~i;i=e[i].nxt) {            if(d[e[i].to]!=d[x]+1) continue;            f=dfs(e[i].to,min(e[i].cap,now));            if(!f) continue;            e[i].cap-=f, e[i^1].cap+=f;            now-=f, flow+=f;            if(!now) break;        }        return flow;    }    int Dinic() {        int maxflow=0;        while(bfs()) {            for(int i=1;i<=n;++i) cur[i]=fir[i];            maxflow+=dfs(S,INF);        }        return maxflow;    }    void build() {        for(int i=0;i<=tot;++i) e[i].cap=w[i>>1];        return ;    }}namespace MincutTree {    struct Edge {        int from,to,nxt,val;        Edge() {}        Edge(int _from,int _to,int _nxt,int _val):            from(_from),to(_to),nxt(_nxt),val(_val) {}    }e[N*2];    int tot,fir[N];    bool k[N*100];    void Add_Edge(int u,int v,int val) {        e[++tot]=Edge(u,v,fir[u],val), fir[u]=tot;        e[++tot]=Edge(v,u,fir[v],val), fir[v]=tot;        return ;    }    void init() {        tot=-1, memset(fir,-1,sizeof fir);        return ;    }    int bfs(int st) {        static int d[N];        int sum=0;        queue<int> q;        for(int i=1;i<=n;++i) d[i]=-1;        q.push(st), d[st]=INF;        while(!q.empty()) {            int x=q.front(); q.pop();            if(x!=st && !k[d[x]]) k[d[x]]=true, ++sum;            for(int i=fir[x];~i;i=e[i].nxt) {                if(d[e[i].to]!=-1) continue;                d[e[i].to]=min(d[x],e[i].val);                q.push(e[i].to);            }        }        return sum;    }    int calc() {        int ans=0;        for(int i=1;i<=n;++i) ans+=bfs(i);        return ans;    }}void solve(int l,int r) {    if(l>=r) return ;    using namespace NetworkFlow;    build();    S=seq[l], T=seq[r];    int v=Dinic();    MincutTree::Add_Edge(S,T,v);    static int tmp[N];    int _l=l,_r=r;    for(int i=l;i<=r;++i)        if(d[seq[i]]!=-1) tmp[_l++]=seq[i];        else tmp[_r--]=seq[i];    for(int i=l;i<=r;++i) seq[i]=tmp[i];    solve(l,_l-1), solve(_r+1,r);    return ;}int main() {    using namespace NetworkFlow;    memset(fir,-1,sizeof fir), tot=-1;    MincutTree::init();    scanf("%d%d",&n,&m);    for(int i=0,x,y;i<m;++i)        scanf("%d%d%d",&x,&y,w+i), Add_Edge(x,y,0);    for(int i=1;i<=n;++i) seq[i]=i;    solve(1,n);    printf("%d\n",MincutTree::calc());    return 0;}