传送门 首先庆祝一下:
为了方便非权限号选手,今后决定在博客中放出题面共参考。 以上内容全是废话 原题就是求补图的连通块个数 不吐就是新建一张图,如果原图中两个点有边,则新图中没边。否则新图中右边。 机智的使用链表+bfs. 链表用来快速维护编号最小的没有被覆盖过的元素。 同时支持删点操作。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 100005 using namespace std; int n,m,ans,tot,x,y; int a[N],q[N],pre[N],nxt[N],head[N],fl[N]; struct edge{int to,next;}e[N*40]; void add(int x,int y){ e[++tot]=(edge){y,head[x]}; head[x]=tot; } void del(int x){ nxt[pre[x]]=nxt[x]; pre[nxt[x]]=pre[x]; } void bfs(int x){ int h=0,t=1,p; q[1]=x; while (h!=t){ p=q[++h]; for (int i=head[p];i;i=e[i].next) fl[e[i].to]=1; for (int i=nxt[0];i<=n;i=nxt[i]) if (!fl[i]) del(i),q[++t]=i; for (int i=head[p];i;i=e[i].next) fl[e[i].to]=0; } a[ans]=t; } int main(){ scanf("%d%d",&n,&m); for (int i=0;i<=n;i++) nxt[i]=i+1; for (int i=1;i<=n+1;i++) pre[i]=i-1; for (int i=1;i<=m;i++){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } for (int i=nxt[0];i<=n;i=nxt[0]){ del(i); ans++; bfs(i); } printf("%d\n",ans); sort(a+1,a+ans+1); for (int i=1;i<=ans;i++) printf("%d ",a[i]); }题面: 1098: [POI2007]办公楼biu
Time Limit: 20 Sec Memory Limit: 162 MB Submit: 1335 Solved: 619 [Submit][Status][Discuss] Description
FGD开办了一家电话公司。他雇用了N个职员,给了每个职员一部手机。每个职员的手机里都存储有一些同事的 电话号码。由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼。FG D希望职员被安置在尽量多的办公楼当中,这样对于每个职员来说都会有一个相对更好的工作环境。但是,为了联 系方便起见,如果两个职员被安置在两个不同的办公楼之内,他们必须拥有彼此的电话号码。
Input
第一行包含两个整数N(2<=N<=100000)和M(1<=M<=2000000)。职员被依次编号为1,2,……,N.以下M行,每 行包含两个正数A和B(1<=A