4519: [Cqoi2016]不同的最小割

来源:互联网 发布:幽灵行动4画面优化 编辑:程序博客网 时间:2024/05/17 23:50

题目链接

题目大意:求两点间最小割取值的个数

题解:套路题~~~

我的收获:最小割树

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <set>using namespace std;#define N 995#define M 99995#define INF 0x3f3f3f3fint n,m;int st,ed;int t,head[N],last[N];int d[N],num[N];int id[N],tmp[N];bool Exit,visit[N];set<int> Tree;struct edge{int to,c,nex;}e[M];void add(int u,int v,int w){e[t]=(edge){v,w,head[u]};last[u]=head[u]=t++;}void insert(int u,int v,int w){add(u,v,w);add(v,u,w);}int dfs(int x,int in){    if(x==ed) return in;    int ans=0,f;    for(int i=last[x];i!=-1;last[x]=i=e[i].nex)    {        int v=e[i].to;        if(e[i].c&&d[v]==d[x]-1){            f=dfs(v,min(in-ans,e[i].c));            ans+=f;e[i].c-=f,e[i^1].c+=f;            if(Exit||ans==in) return ans;        }    }    if(--num[d[x]]==0) Exit=1;    d[x]++,num[d[x]]++,last[x]=head[x];    return ans;}int Isap(){    memset(d,0,sizeof(d));    memset(num,0,sizeof(num));num[0]=n;    Exit=0;int flow=0;    while(!Exit) flow+=dfs(st,INF);    return flow;}void DFS(int x){    if(visit[x]) return ;    visit[x]=1;    for(int i=head[x];i!=-1;i=e[i].nex)    if(e[i].c) DFS(e[i].to);}void solve(int l,int r){    if(l==r) return;    for(int i=0;i<t;i+=2) e[i].c=e[i^1].c=(e[i].c+e[i^1].c)>>1;     st=id[l],ed=id[r];    Tree.insert(Isap());    memset(visit,0,sizeof(visit));DFS(st);    int x=l,y=r;    for(int i=l;i<=r;i++)    if(visit[id[i]]) tmp[x++]=id[i];    else tmp[y--]=id[i];    for(int i=l;i<=r;i++) id[i]=tmp[i];    solve(l,x-1);solve(y+1,r);} void work(){    solve(1,n);    cout<<Tree.size()<<endl;}void init(){    cin>>n>>m;    memset(head,-1,sizeof(head));    memset(last,-1,sizeof(last));    for(int x,y,z,i=1;i<=m;i++) cin>>x>>y>>z,insert(x,y,z);    for(int i=1;i<=n;i++) id[i]=i;}int main(){    init();    work();    return 0;}