说在前面
me记得me打的唯一一场CF里面有这道题,当时me写的数据分治被hack掉了(绝望)
然后交到这里又TLE掉了emmmm…
今天终于把坑填了
题目
题目大意
现在给出一张
n
n
个点的图,其中有 条边没有(也就是说,没有给出的边是存在的,给出的边是不存在的)
现在询问该图的反图的连通块个数,以及每个连通块的大小
范围:
n≤105
n
≤
10
5
,
m≤106
m
≤
10
6
输入输出格式
输入格式:
第一行两个整数
n,m
n
,
m
,含义如题
接下来
m
m
行,每行两个整数描述一条不存在的边
输出格式:
先输出一行一个整数 ,表示反图连通块个数
然后再输出一行
k
k
个整数,表示每个块的大小,从小到大依次输出
解法
我们回顾一下正图的遍历,因为边很少,所以对于每个点,可以直接枚举它连的边进行BFS/DFS,复杂度是
但是对于反图,我们不能再去枚举有哪些边,而要去枚举没有哪些边,然后继续遍历和它相临的点
因为要保证复杂度,对于每个点我们只能遍历一次,所以我们需要记录下哪些点还没有被遍历,这个可以用一个set/链表来维护
对于BFS的写法:
每次查找与当前点
u
u
相连的点时,先把所有与 无边的点 ban 掉,然后枚举还没有被遍历的点
v
v
,如果 没被 ban 掉,说明
v
v
和 相连,然后把
v
v
加进队列
这样的话,每个点每条边都只会被访问一次,复杂度就ok了
对于DFS的写法:
每次都从未遍历集合取出一个点 ,判断是否与当前点有边,如果有,把
v
v
移出集合,然后进入 继续dfs
下面是代码
me用的BFS实现
#include <set>
#include <cstdio>
#include <cstring>
#include <functional>
#include <algorithm>
using namespace std ;
int N , M , head[100005] , tp , fa[100005] ;
struct Path{
int pre , to ;
}p[4000005] ;
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 } ; head[t2] = tp ;
}
int find( int x ){
if( fa[x] == x ) return x ;
return fa[x] = find( fa[x] ) ;
}
int cnt[100005] , tot ;
bool vis[100005] ;
set<int> s0 , s1 ;
void solve(){
for( int i = 1 ; i <= N ; i ++ )
fa[i] = i , s1.insert( i ) ;
while( !s1.empty() ){
int u , f ;
if( !s0.empty() ) u = *s0.begin() , s0.erase( s0.begin() ) ;
else u = *s1.begin() , s1.erase( s1.begin() ) ;
f = find( u ) ;
for( int i = head[u] ; i ; i = p[i].pre )
vis[ p[i].to ] = true ;
for( set<int>::iterator it = s1.begin() ; it != s1.end() ; ){
int v = (*it) ; ++ it ;
if( vis[v] ) continue ;
fa[ find( v ) ] = f , s1.erase( v ) , s0.insert( v ) ;
}
for( int i = head[u] ; i ; i = p[i].pre )
vis[ p[i].to ] = false ;
}
for( int i = 1 ; i <= N ; i ++ ) cnt[ find( i ) ] ++ ;
sort( cnt + 1 , cnt + N + 1 , greater<int>() ) ;
for( int i = 1 ; !tot ; i ++ ) if( !cnt[i] ) tot = i - 1 ;
printf( "%d\n" , tot ) ;
for( int i = tot ; i ; i -- ) printf( "%d " , cnt[i] ) ;
}
int main(){
scanf( "%d%d" , &N , &M ) ;
for( int i = 1 , u , v ; i <= M ; i ++ ){
scanf( "%d%d" , &u , &v ) ;
In( u , v ) ;
} solve() ;
}