【CERC2015】【BZOJ4435】Juice Junctions

Description

你被雇佣升级一个旧果汁加工厂的橙汁运输系统。系统有管道和节点构成。每条管道都是双向的,且每条管道的流量都是1升每秒。管道可能连接节点,每个节点最多可以连接3条管道。节点的流量是无限的。节点用整数1到n来表示。在升级系统之前,你需要对现有系统进行分析。对于两个不同节点s和t,s-t的流量被定义为:当s为源点,t为汇点,从s能流向t的最大流量。以下面的第一组样例数据为例,1-6的流量为3,1-2的流量为2。计算每一对满足a< b的节点a-b的流量的和。

Input

第一行包括2个整数n和m(2<=n<=3000,0<=m<=4500)——节点数和管道数。
接下来m行,每行包括两个相异整数a,b(1<=a,b<=n),表示一条管道连接节点a,b。
每个节点最多连接3条管道,每对节点最多被一条管道连接。

Output

输出一个整数——每对满足a< b的节点a-b的流量之和。

Sample Input

6 8

1 3

2 3

4 1

5 6

2 6

5 1

6 4

5 3
Sample Output

36
HINT

Source

考虑割流转化,然后做最小割树,最后把流量Hash出来统计
Claris说此题卡ISAP和Dinic常数,要用EK才行..

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 3010
#define GET (ch>='0'&&ch<='9')
using namespace std;
int n,m,top,ans,S,T,ret;
int num[MAXN],tmp[MAXN],q[MAXN],h[MAXN];
unsigned hash[4][MAXN],Pow=1;
struct edge {   int st,to,c,id; edge *next,*rev;    }e[MAXN<<2],*prev[MAXN];
inline void insert(int u,int v,int c)   {   e[++top].to=v;e[top].st=u;e[top].next=prev[u];prev[u]=&e[top];e[top].c=c;e[top].id=top; }
inline void add(int u,int v,int c)  {   insert(u,v,c);insert(v,u,c);prev[u]->rev=prev[v];prev[v]->rev=prev[u];    }
inline void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
bool bfs()
{
    int l=0,r=1;memset(h+1,-1,sizeof(int)*n);h[q[0]=S]=0;
    while (l<r)  for (edge *i=prev[q[l++]];i;i=i->next)   if (h[i->to]<0&&i->c)  q[r++]=i->to,h[i->to]=i->id;
    return h[T]!=-1;
}
void solve(int l,int r)
{
    if (l>=r)    return;
    for (int i=1;i<=top;i+=2)    e[i].c=e[i].rev->c=1;
    S=num[r];T=num[l];ret=0;int j;
    while (bfs())   
    {
        ret++;
        for (int i=T;i!=S;i=e[j].st)    e[j=h[i]].c--,e[j].rev->c++;
    }
    Pow*=233;
    for (int i=1;i<=n;i++)   if (~h[i])  hash[ret][i]+=Pow;
    int L=l,R=r;
    for (int i=l;i<=r;i++)   if (h[num[i]]<0) tmp[L++]=num[i];    else    tmp[R--]=num[i];
    memcpy(num+l,tmp+l,sizeof(int)*(r-l+1));solve(l,R);solve(L,r);
}
int main()
{
    in(n);in(m);int u,v;
    for (int i=1;i<=m;i++)   in(u),in(v),add(u,v,1);
    for (int i=1;i<=n;i++)   num[i]=i;
    solve(1,n);
    for (int i=1;i<=n;i++)   for (int j=i+1;j<=n;j++) for (int k=0;k<4;k++)
        if (hash[k][i]!=hash[k][j]) {   ans+=k;break;   }
    cout<<ans<<endl;
}

你可能感兴趣的:(hash,割流转化,最小割树)