ABC131F题解
感觉这题比较偏 CF 风格。
先脚造几组数据手玩一下,发现每一个点就像一条边一样把行和列连了起来,而每一个连起来的块内点的大小是正好填满的。
自然想到并查集。
将每一个点的 $x$ 和 $y$ 通过并查集连起来,扫的时候用 unordered_set
维护这个并查集中横坐标的个数和纵坐标的个数,两个大小相乘,最后减掉 $n$ 即可。
code
#include <bits/stdc++.h>
#include <unordered_set>
#define LL long long
using namespace std;
struct edge{
LL to,nt;
}a[200005];
LL n,i,j,k,m,ans=0,cnt1=0;
LL fa[200005],cnt[200005],sum[200005],x[200005],y[200005],nxt[200005];
unordered_set<LL> st1[200005],st2[200005];
LL father(LL x){
if(fa[x]!=x) return fa[x]=father(fa[x]);
else return x;
}
void add(LL x,LL y){
a[++cnt1].to=y;a[cnt1].nt=nxt[x];nxt[x]=cnt1;
}
int main() {
scanf("%lld",&n);
for(i=1;i<=200000;i++)
fa[i]=i;
for(i=1;i<=n;i++){
scanf("%lld%lld",&x[i],&y[i]);
cnt[x[i]]++;cnt[y[i]+100000]++;
add(x[i],y[i]);add(y[i]+100000,x[i]);
if(father(x[i])!=father(y[i]+100000)) fa[fa[y[i]+100000]]=fa[x[i]];
}
for(i=1;i<=200000;i++){
if(i<=100000){
for(j=nxt[i];j;j=a[j].nt)
st1[father(i)].insert(a[j].to);
}
else {
for(j=nxt[i];j;j=a[j].nt)
st2[father(i)].insert(a[j].to);
}
}
for(i=1;i<=100000;i++)
ans+=st1[i].size()*st2[i].size();
printf("%lld",ans-n);
return 0;
}