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;
}
posted @ 2023-09-24 19:47  monster_hunterqwq  阅读(11)  评论(0编辑  收藏  举报  来源