1. 程式人生 > >HDU6184 Counting Stars

HDU6184 Counting Stars

題意:

Little A is an astronomy lover, and he has found that the sky was so beautiful! So he is counting stars now! There are n stars in the sky, and little A has connected them by m non-directional edges. It is guranteed that no edges connect one star with itself, and every two edges connect different pairs of stars. Now little A wants to know that how many different "A-Structure"s are there in the sky, can you help him? An “A-structure” can be seen as a non-directional subgraph G, with a set of four nodes V and a set of five edges E. If V=(A,B,C,D) and E=(AB,BC,CD,DA,AC), we call G as an “A-structure”. It is defined that “A-structure” G1=V1+E1 and G2=V2+E2 are same only in the condition that V1=V2 and E1=E2.

資料範圍:

n105,m2105n\leq{10^5},m\leq{2*10^5}

Analysis:

翻譯不是這題的重點,我們來講講這題真正要求的東西,其實就是懶得翻譯,英文不好。 事實上就是讓我們三元環計數,找出一條邊存在於多少個三元環中。 我們考慮一種暴力:列舉一個點,列舉所有出邊的點打上標記,再枚舉出邊,然後枚舉出邊的點的出邊,看出邊的點是否有標記,語文功底太差,超級繞 。我們設一個點的出度為outvout_v,不難發現這樣的複雜度為eu,voutu+outv\sum_{e_{u,v}}out_u+out_v。讓每條邊只會被列舉兩次。 考慮平衡出度,我們強制讓度數小的連向度數大的點(有向邊),度數相同按編號有序連邊。 不難發現會是一張D

agDag,因為如果有環的話,編號的偏序關係會矛盾。原先的三元環仍然可以如上列舉,且僅會被列舉一次,因為必定會有且僅有一個點入度為22。 這樣複雜度變為eu,voutv\sum_{e_{u,v}}out_v,那麼每個點出度為多少呢,是不會超過m\sqrt{m}的。 考慮反證:若一個點出度超過m\sqrt{m},因為連出去的點出度都大於其,所以至少m\sqrt{m}個點,每個點至少m\sqrt{m}條出邊,出邊總數大於mm ,所以與條件矛盾。 那麼總複雜度為O(mm)O(m\sqrt{m})。比較優秀,常數也比較小。 至於統計答案,只要算出每條邊存在於多少個三元環,然後C
cnt2C_{cnt}^2
加起來就好。

Code:

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
int st[N],to[N << 1],nx[N << 1],id[N << 1];
int vis[N][2],D[N],e[N << 1][2],cnt[N << 1];
int n,m,tot;
inline void add(int u,int v,int w)
{ to[++tot] = v,nx[tot] = st[u],id[tot] = w,st[u] = tot; }
int main()
{
	while (~scanf("%d%d",&n,&m))
	{
		memset(vis,0,sizeof(vis)),memset(st,0,sizeof(st)),memset(cnt,0,sizeof(cnt)),memset(D,0,sizeof(D)),tot = 0;
		for (int i = 1 ; i <= m ; ++i) scanf("%d%d",&e[i][0],&e[i][1]),++D[e[i][0]],++D[e[i][1]];
		for (int i = 1 ; i <= m ; ++i)
		{
			if (e[i][0] > e[i][1]) swap(e[i][0],e[i][1]);
			if (D[e[i][0]] > D[e[i][1]]) swap(e[i][0],e[i][1]);
			add(e[i][0],e[i][1],i);
		}
		for (int i = 1 ; i <= n ; ++i)
		{ 
			for (int j = st[i] ; j ; j = nx[j]) vis[to[j]][0] = i,vis[to[j]][1] = j;
			for (int j = st[i] ; j ; j = nx[j])
				for (int k = st[to[j]] ; k ; k = nx[k])
				if (vis[to[k]][0] == i) ++cnt[id[j]],++cnt[id[k]],++cnt[vis[to[k]][1]];
		}
		ll ans = 0;
		for (int i = 1 ; i <= m ; ++i) if (cnt[i] > 1) ans += (ll)(cnt[i] - 1) * cnt[i] / 2;
		printf("%lld\n",ans);
	}
	return 0;
}