点接通分量

点连通分量
Gymman vs Fila
Time Limit:2000MS   Memory Limit:Unknown   64bit IO Format:%lld & %llu

[Submit]  [Go Back]  [Status]  

Description

点接通分量


  Gymman vs Fila 

The great king Gymman and his queen Asira were living together happily. But an evil magician the evil Fila, who is trying to get hold of the throne had made a plan to separate the king and queen to get hold of the throne.

There were many cities in the kingdom. All of them were connected with bidirectional roads. He planned to send the king and queen into two different cities giving wrong messages, as without the queen, king would be very sad and unable to continue ruling. The evil fila succeeded on his task, as king and queen are not evil and they believed him. Though now king and queen lives in different city they frequently communicate with each other. The communication took place through letters and to exchange letters in kingdom the two corresponding cities should be connected through one or more bidirectional roads.

After the separation of king and queen, a natural calamity came into the kingdom and destroyed some of the bidirectional roads. If the king and queen still can communicate with each other Fila have to block communication between them. But he can occupy only one city and siege the letter carrier. King got this information of the evil plan.

Now he wants to know according to Fila's plan how many different combination of 3 cities a, b, c ( a点接通分量b点接通分量c) exists such that king will be on city a, queen will be on city b and evil Fila will be on city c and Fila can block communication between king and queen. Two combinations ( x1, y1, z1) and ( x2, y2, z2) will be same if x1 and x2 are same, y1 and y2 are same and z1 and z2 are same. As Fila is an evil magician, he can go to any city with his magical power without the help of road transports.

Input 

First line contains T ( 1 < T < 21), the number of test cases to follow.

For each test case, in the 1st line there will be 2 integers N ( 1点接通分量N点接通分量20000) and M ( 0点接通分量M点接通分量100000). N is the number of cities and M is the number of roads between them.

M lines follow, each containing two integers u and v. That means there is a bidirectional road between city u and city v. The cities are numbered from 1 to N. All roads will be distinct and connect two different cities.

Output 

For each case, print the test case number starting from 1 and the number of combinations in one line. See sample output for exact formatting.


Explanation:

In 2-nd test case, 4 triplets are (1, 2, 3), (1, 4, 3), (2, 1, 3) and (4, 1, 3).

In 3-rd test case, 2 triplets are (4, 6, 5) and (6, 4, 5).

Sample Input 

3
3 3
1 2
2 3
1 3
4 4
2 4
4 3
2 3
3 1
6 5
1 2
2 3
1 3
4 5
5 6

Sample Output 

Case 1: 0
Case 2: 4
Case 3: 2


求有多少对这种组合,[x,y,z],去掉点y,那么x,y就断开,双连通缩点,然后枚举割点,新学习别人的建图方法。

代码:

/* ***********************************************
Author :rabbit
Created Time :2014/4/15 15:58:56
File Name :F.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
const int maxn=100100;
int head[maxn],tol;
int low[maxn],dfn[maxn],indexx,cut[maxn],block,st[maxn],top;
int n,m;
vector<int> node[maxn],com[maxn],G[maxn];
int cnt[maxn];
struct Edge{
	int from,to,vis,next;
	Edge(int _from=0,int _to=0,int _vis=0,int _next=0){
		from=_from;to=_to;vis=_vis,next=_next;
	}
}edge[5*maxn];
void addedge(int u,int v,int vis){
	edge[tol]=Edge(u,v,vis,head[u]);
	head[u]=tol++;
}
void tarjan(int u,int pre){
	low[u]=dfn[u]=++indexx;
	int son=0;
	for(int i=head[u];i!=-1;i=edge[i].next){
		if(edge[i].vis)continue;
		st[top++]=i;
		edge[i].vis=edge[i^1].vis=1;
		int v=edge[i].to;
		if(!dfn[v]){
			tarjan(v,u);
			son++;
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				if(u!=pre)cut[u]=1;
				++block;
				int s,t,k;
				com[block].clear();
				do{
					k=st[--top];
					s=edge[k].from;
					t=edge[k].to;
					com[block].push_back(s);
					com[block].push_back(t);
					node[s].push_back(block);
					node[t].push_back(block);
				}while(s!=u);
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(u==pre&&son>1)cut[u]=1;
}
void bcc(int n){
	indexx=top=block=0;
	memset(dfn,0,sizeof(dfn));
	memset(cut,0,sizeof(cut));
	for(int i=1;i<=n;i++)node[i].clear();
	for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,i);
	for(int i=1;i<=n+block;i++)G[i].clear();
	for(int i=1;i<=n;i++)if(cut[i]){
		sort(node[i].begin(),node[i].end());
		node[i].resize(unique(node[i].begin(),node[i].end())-node[i].begin());
		for(int j=0;j<node[i].size();j++){
			int x=i,y=node[i][j]+n;
			G[x].push_back(y);
			G[y].push_back(x);
		}
	}
}
ll ans,cur,dp[maxn];
bool vis[maxn],mark[maxn];
void find(int u){
	cur+=cnt[u];
	mark[u]=1;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		if(!mark[v])find(v);
	}
}
void dfs(int u){
	dp[u]=0;vis[u]=1;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		if(vis[v])continue;
		dfs(v);
		if(cut[u])ans+=dp[u]*dp[v];
		dp[u]+=dp[v];
	}
	dp[u]+=cnt[u];
	if(cut[u])ans+=(dp[u]-1)*(cur-dp[u]);
}
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int T,t;
	 scanf("%d",&T);
	 for(int t=1;t<=T;t++){
		 memset(head,-1,sizeof(head));tol=0;
		 scanf("%d%d",&n,&m);
		 while(m--){
			 int x,y;scanf("%d%d",&x,&y);
			 addedge(x,y,0);
			 addedge(y,x,0);
		 }
		 bcc(n);
		// cout<<"block="<<block<<endl;
		 memset(cnt,0,sizeof(cnt));
		 for(int i=1;i<=n;i++)if(cut[i])cnt[i]=1;
		 for(int i=1;i<=block;i++){
			 sort(com[i].begin(),com[i].end());
			 com[i].resize(unique(com[i].begin(),com[i].end())-com[i].begin());
			 for(int j=0;j<com[i].size();j++)if(!cut[com[i][j]])cnt[i+n]++;
		 }
		 memset(vis,0,sizeof(vis));
		 ans=0;
		 for(int i=1;i<=n+block;i++)if(!vis[i]){
			 memset(mark,0,sizeof(bool)*(n+block+100));
			 cur=0;
			 find(i);
			 dfs(i);
		 }
		 printf("Case %d: %lld\n", t, ans<<1);
	 }
     return 0;
}