1. 程式人生 > >4264:小C找朋友(hash)

4264:小C找朋友(hash)

小C找朋友

題目描述

幼兒園裡有 N 個小 C ,兩個小 C

之間可能是朋友也可能不是。所有小 C 之間的朋友關係構成了一個無向圖,這個無向圖中有 M 條邊。

園長ATM發現對於兩個(不同的)小

C i C j ,如果其他的所有小
C
要麼同時是 i , j 的朋友,要麼同時不是 i , j 朋友的話,這兩個小 C 就很有可能一起去吃飯,成為一對好基友。出於一些未知的原因,ATM需要你幫他求出可能成為好基友的小C的對數。

輸入

第一行一個數 N , M ,如題目描述。
接下來 M 行,每行2個數表示一條無向邊。

輸出

輸出可能成為好基友的小 C 的對數。

輸入樣例

3 3
1 2
2 3
1 3

輸出樣例

3

提示

N , M 1000000















解:

一道很簡單的題目。如何快速判斷連邊相等?自然而然想到了hash。把一個點連向的邊全部異或起來存在這個點裡,然後朋友一樣的點的值相同。但是他們兩個如果是朋友的話這個值就不一樣了。於是我們再異或一下自己再做一遍。
但是這樣容易衝突。我們給每個點rand一個 l o n g l o n g 權值,再那麼做就好啦。(開個map存一下)

code:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<map>
using namespace std;

unsigned long long r[1000005];
unsigned long long p[1000005];
map <unsigned long long,int> d;
int n,m,x,y;
long long ans;

int main()
{
    srand(19260817);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) r[i]=1ll*rand()*rand()*rand()*rand()*rand();
    for(int i=1;i<=m;i++)
      scanf("%d%d",&x,&y),p[x]^=r[y],p[y]^=r[x];
    for(int i=1;i<=n;i++){
        ans+=d[p[i]];
        d[p[i]]++;
    }
    d.clear();
    for(int i=1;i<=n;i++) p[i]^=r[i];
    for(int i=1;i<=n;i++){
        ans+=d[p[i]];
        d[p[i]]++;
    }
    printf("%lld",ans);
}