adjective
2025-01-09 18:46:19
$1 \le n,m \le 2 \times 10^5$。
最后
考虑枚举
按编号从小到大枚举
用并查集维护连通块,用 set
记录相邻的 set
,再与相邻的 set
的大小。启发式合并,时间复杂度
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define pb push_back
#define U(x) ((int)x.size())
const int N=2e5+100;
#define gc getchar()
#define rd read()
inline int read(){
int x=0,f=0; char c=gc;
for(;c<'0'||c>'9';c=gc) f|=(c=='-');
for(;c>='0'&&c<='9';c=gc) x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
int n,m; ll ans=0;
vector<int> G[N];
int fa[N],siz[N]; set<int> s[N];
void init(){ for(int i=1;i<=n;++i) fa[i]=i,siz[i]=1; }
int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); }
void mer(int x,int y){
x=find(x),y=find(y); if(x==y) return;
if(siz[x]<siz[y]) swap(x,y);
fa[y]=x,siz[x]+=siz[y]; for(auto v:s[y]) s[x].insert(v);
}
int main(){
n=rd,m=rd,init();
for(int i=1,x,y;i<=m;++i) G[x=rd].pb(y=rd),G[y].pb(x);
for(int u=1;u<=n;++u){
for(int v:G[u]) if(v>u) s[u].insert(v);
for(int v:G[u]) if(v<u) mer(v,u);
if(s[find(u)].count(u)) s[find(u)].erase(u); //此时 u 不是 0 点,如果有要删去。
ans+=U(s[find(u)]);
}
printf("%lld\n", ans-m);
return 0;
}