zoukankan      html  css  js  c++  java
  • [BZOJ4435][Cerc2015]Juice Junctions

    bzoj
    luogu

    description

    给你一张(n)(m)条边的无向图,保证每个点的度数不超过(3)。每条边容量为(1),求所有点对之间的最大流之和。
    (nle3000,mle4500)

    sol

    据说这题可以用最小割树跑过去。。。(mbox{orz})
    考虑一些靠谱一点的算法。因为最大流等于最小割,而一个点的度数不超过(3),所以任意两点之间的最大流应该(in{0,1,2,3})
    对于所有最大流(in{1,2,3})的点对,它们满足连通。
    对于所有最大流(in{2,3})的点对,它们满足在同一个边双连通分量中。
    对于所有最大流(=3)的点对,它们满足什么?
    满足任意删除一条边之后,它们仍在同一个边双连通分量中。
    所以就每次删一条边然后跑边双,(mbox{hash})一下所处的边双连通分量的编号就好啦。
    复杂度(O(nm))

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    #define ull unsigned long long
    const int N = 3005;
    const int base1 = 20011118;
    const int base2 = 20020415;
    int n,m,fa[N],to[N*3],nxt[N*3],head[N],cnt=1,dfn[N],low[N],tim,S[N],bel[N],scc,ban,ans;
    ull hsh1[N],hsh2[N];
    void link(int u,int v){
    	to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
    }
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    void Tarjan(int u,int f){
    	dfn[u]=low[u]=++tim;S[++S[0]]=u;
    	for (int e=head[u];e;e=nxt[e]){
    		if (to[e]==f||e==ban||e==(ban^1)) continue;
    		if (!dfn[to[e]]) Tarjan(to[e],u),low[u]=min(low[u],low[to[e]]);
    		else low[u]=min(low[u],dfn[to[e]]);
    	}
    	if (dfn[u]==low[u]){
    		++scc;int x=0;
    		do x=S[S[0]--],bel[x]=scc; while (x!=u);
    	}
    }
    int main(){
    	n=gi();m=gi();
    	for (int i=1;i<=n;++i) fa[i]=i;
    	for (int i=1;i<=m;++i){
    		int u=gi(),v=gi();
    		link(u,v),link(v,u);
    		fa[find(u)]=find(v);
    	}
    	for (int i=1;i<=n;++i) if (!dfn[i]) Tarjan(i,0);
    	for (int i=1;i<=n;++i)
    		for (int j=i+1;j<=n;++j)
    			ans+=(find(i)==find(j))+(bel[i]==bel[j]);
    	for (int i=1;i<=m;++i){
    		memset(dfn,0,sizeof(dfn));tim=scc=0;
    		ban=i<<1;
    		for (int j=1;j<=n;++j) if (!dfn[j]) Tarjan(j,0);
    		for (int j=1;j<=n;++j) hsh1[j]=hsh1[j]*base1+bel[j],hsh2[j]=hsh2[j]*base2+bel[j];
    	}
    	for (int i=1;i<=n;++i)
    		for (int j=i+1;j<=n;++j)
    			ans+=(hsh1[i]==hsh1[j]&&hsh2[i]==hsh2[j]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    hdu 4521 小明系列问题——小明序列(线段树 or DP)
    hdu 1115 Lifting the Stone
    hdu 5476 Explore Track of Point(2015上海网络赛)
    Codeforces 527C Glass Carving
    hdu 4414 Finding crosses
    LA 5135 Mining Your Own Business
    uva 11324 The Largest Clique
    hdu 4288 Coder
    PowerShell随笔3 ---别名
    PowerShell随笔2---初始命令
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9426493.html
Copyright © 2011-2022 走看看