4264: 小C找朋友
Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 28 Solved: 10
[ Submit][ Status][ Discuss]
Description
幼儿园里有N个小C,两个小C之间可能是朋友也可能不是。所有小C之间的朋友关系构成了一个无向图,这个无向图中有M条边。
园长ATM发现对于两个(不同的)小Ci和j,如果其他的所有小C要么同时是i,j的朋友,要么同时不是i,j朋友的话,这两个小C就很有可能一起去吃饭,成为一对好*友。出于一些未知的原因,ATM需要你帮他求出可能成为好*友的小C的对数。
Input
第一行一个数N,M,如题目描述。
接下来M行,每行2个数表示一条无向边。
Output
输出可能成为好*友的小C的对数。
Sample Input
3 3
1 2
2 3
1 3
1 2
2 3
1 3
Sample Output
3
HINT
N,M<=1000000
若x与y可能成为好*友,那么它们连出去的点除了x和y之外都相同。
于是给每个点一个long long的随机权值,然后每个点的hash值为与其相连的点的权值的异或和,若两个点hash值相等,则可行。
给每个点的hash值异或上自己本身的权值再求一次即可得到正确答案。
时间复杂度 O(nlogn) 。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#define LL long long
using namespace std;
const long long MAXN = 1000000 + 10;
long long a[MAXN];
long long b[MAXN];
long long h[MAXN];
long long n, m;
int main()
{
while(scanf("%lld%lld", &n, &m)!=EOF)
{
long long u, v;
long long r = 0;
for(long long i=1;i<=n;i++) h[i] = r = r * 233 + 17;
for(long long i=1;i<=n;i++) a[i] = 0;
for(long long i=1;i<=m;i++)
{
scanf("%lld%lld", &u, &v);
a[u] ^= h[v];a[v] ^= h[u];
}
for(long long i=1;i<=n;i++) b[i] = a[i] ^ h[i];
sort(a + 1 , a + 1 + n);
long long ans = 0;long long i, j;
for(i=j=1;i<=n;i++) if(a[i] != a[j]) ans += 1LL * (i - j) * (i - j - 1) / 2, j = i;
ans += 1LL * (n - j) * (n - j + 1) / 2;
sort(b + 1 , b + 1 + n);
for(i=1,j=1;i<=n;i++) if(b[i] != b[j]) ans += 1LL * (i - j) * (i - j - 1) / 2, j =i;
ans += 1LL * (n - j) * (n - j + 1) / 2;
printf("%lld\n", ans);
}
return 0;
}