BZOJ2730: [HNOI2012]矿场搭建

传送门

图的连通性相关的必和割点割边之类的有关。

题目要求对于一个无向图,任意一点被删除后,所有点都和某些指定点是联通的。

这道题比较简单的做法就是求出来所有的。对于一个块,如果块里有两个及两个以上的割点,那么这个块是不需要钦定点的。两个一下的需要分类讨论。

对于只有一个割点的,肯定要钦定一个点,不然割点挂了整个块就GG了。

对于不存在割点的,要钦定一个点和一个备胎点,免得钦定的点被炸了。

求方案数可以用乘法原理。同样,存在两个及两个以上割点的块不需要考虑,一个和不存在的需要分类讨论。

对于只有一个割点的块,可以挑选的点有$size-1$个。

对于一个割点都没有的块,可以挑选的点有$size \times (size-1)$个。

累乘起来就行了。

//BZOJ 2730
//by Cydiater
//2016.11.1
#include <iostream>
#include <cstdlib>
#include <queue>
#include <map>
#include <ctime>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
#include <bitset>
#include <set>
#include <iomanip>
using namespace std;
#define ll long long
#define up(i,j,n)		for(int i=j;i<=n;i++)
#define down(i,j,n)		for(int i=j;i>=n;i--)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
#define Auto(i,node)		for(int i=LINK[node];i;i=e[i].next)
const int MAXN=1e5+5;
const int oo=0x3f3f3f3f;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int N,M,LINK[MAXN],len=0,dfn[MAXN],low[MAXN],dfs_clock=0,color_num=0,color[MAXN],casenum=0;
bool iscut[MAXN],vis[MAXN];
ll ans1,ans2,siz,cutnum;
struct edge{
	int y,next;
}e[MAXN];
namespace solution{
	inline void insert(int x,int y){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;}
	inline void Insert(int x,int y){insert(x,y);insert(y,x);}
	void tarjan(int node,int father){
		dfn[node]=low[node]=++dfs_clock;
		int child=0;
		Auto(i,node)if(e[i].y!=father){
			if(!dfn[e[i].y]){
				tarjan(e[i].y,node);child++;
				cmin(low[node],low[e[i].y]);
				if(low[e[i].y]>=dfn[node])iscut[node]=1;
			}else cmin(low[node],dfn[e[i].y]);
		}
		if(father==0&&child==1)iscut[node]=0;
	}
	void dfs(int node){
		color[node]=color_num;if(iscut[node])return;siz++;
		Auto(i,node){
			if(iscut[e[i].y]&&color[e[i].y]!=color_num){
				cutnum++;color[e[i].y]=color_num;
			}
			if(!color[e[i].y])dfs(e[i].y);
		}
	}
	void slove(){
		N=len=dfs_clock=0;
		memset(LINK,0,sizeof(LINK));
		memset(iscut,0,sizeof(iscut));
		up(i,1,M){int x=read(),y=read();cmax(N,max(x,y));Insert(x,y);}
		memset(dfn,0,sizeof(dfn));
		up(i,1,N)if(!dfn[i])tarjan(i,0);
		memset(color,0,sizeof(color));
		color_num=0;ans1=0;ans2=1;
		up(i,1,N)if(!iscut[i]&&!color[i]){
			color_num++;siz=cutnum=0;dfs(i);
			if(cutnum==0){ans1+=2;ans2*=(ll)siz*(ll)(siz-1)/2;}
			if(cutnum==1){ans1++;ans2*=(ll)siz;}
		}
		printf("Case %d: %lld %lld\n",++casenum,ans1,ans2);
	}
}
int main(){
	//freopen("input.in","r",stdin);
	using namespace solution;
	while(scanf("%d",&M)!=EOF)if(M!=0)slove();
	return 0;
}
上一篇:[Unity3D插件]2dtoolkit系列二 动画精灵的创建以及背景图的无限滚动


下一篇:cmake 添加头文件目录,链接动态、静态库