思路题+链表--bzoj1098: [POI2007]办公楼biu

传送门
本质上是求补图的每个联通块大小
考虑 b f s bfs bfs,枚举每个未访问的点作为起点,然后将与他连边的点都标记一下放到一个栈里,然后将他删除,在栈里的点也是这么做的,这样就可以处理出这个联通块大小,可以用链表维护

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100005
#define M 2000005
using namespace std;
int n,m,cnt,head[N],to[M<<1],nxt[M<<1];
int l[N],r[N],stk[N],top,vis[N],siz[N],tot;

inline int rd(){
    int x=0,f=1;char c=' ';
    while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
    while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
    return x*f; 
}

inline void add(int x,int y){
	to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt;
	to[++cnt]=x; nxt[cnt]=head[y]; head[y]=cnt;
}

inline void del(int now){
	l[r[now]]=l[now],r[l[now]]=r[now];
} 

int main(){
	n=rd(); m=rd();
	for(int i=1;i<=m;i++){
		int a=rd(),b=rd();
		add(a,b);
	}
	for(int i=1;i<=n;i++)
		l[i]=i-1,r[i]=i+1;
	int cur=1;
	while(cur<=n){
		siz[++tot]=1;
		for(int i=head[cur];i;i=nxt[i]) vis[to[i]]=cur;
		del(cur); int now=r[0];
		while(now<=n){
			if(vis[now]!=cur) stk[++top]=now,siz[tot]++,del(now);
			now=r[now];
		}
		while(top){
			int u=stk[top--];
			for(int i=head[u];i;i=nxt[i]) vis[to[i]]=u;
			now=r[0];
			while(now<=n){
				if(vis[now]!=u) stk[++top]=now,siz[tot]++,del(now);
				now=r[now];
			}
		}
		cur=r[0];
	}
	printf("%d\n",tot);
	sort(siz+1,siz+tot+1);
	for(int i=1;i<=tot;i++)
		printf("%d ",siz[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值