BZOJ 4264 小C找朋友


題目大意:給定一張無向圖,求有多少對點 (x,y)(xy) 滿足對於任意一點 z(zx,zy) 滿足邊 (x,z) 和邊 (y,z) 要么都存在,要么都不存在

對於一個點 x 我們搞出與這個點相鄰的點的集合 Adj(x)
那么如果 (x,y) 之間沒有邊那么點對 (x,y) 滿足條件等價於 Adj(x)=Adj(y)
如果 (x,y) 之間有邊那么點對 (x,y) 滿足條件等價於 Adj(x)y=Adj(y)x

怎么表示一個集合呢?我們給一個點賦予一個64位的整數,然后一個集合用集合內所有的點的異或值來代替就行了
然后一個集合就變成了一個數,沒有邊的排序處理,有邊的枚舉邊就行了
時間復雜度 O(nlogn+m)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1001001
using namespace std;
struct edge{
int x,y;
}edges[M];
int n,m;
long long a[M],b[M],ans;
int main()
{
srand(19980402);
int i,x,y;
cin>>n>>m;
for(i=1;i<=n;i++)
a[i]=(long long)rand()*rand()+rand();
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
edges[i].x=x;
edges[i].y=y;
b[x]^=a[y];
b[y]^=a[x];
}
for(i=1;i<=m;i++)
{
x=edges[i].x;
y=edges[i].y;
if( (b[x]^a[y])==(b[y]^a[x]) )
++ans;
}
sort(b+1,b+n+1);
int cnt=0;
for(i=1;i<=n;i++)
{
++cnt;
if(i==n||b[i]!=b[i+1])
ans+=(long long)cnt*(cnt-1)>>1,cnt=0;
}
cout<<ans<<endl;
return 0;
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com