bzoj1098: [POI2007]办公楼biu
做法就是任选一个人新建一个楼子扔它进去,然后把它没有号码的所有人和它放在一个办公楼,其他人也这样操作(就是宽搜),扔无可扔为止
但是这样每次枚举复杂度很高,考虑开一个全局的链表,已经有楼子住的人就删掉。
那么如何快速判断是否有号码呢?我们可以开一个bool数组,每次宽搜到当前点就先把这些有号码的点打上标记,结束再清空,从而保证O(n+m)的复杂度
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[4100000];int len,last[110000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int n,m,aslen,as[110000],L[110000],R[110000]; int list[110000];bool v[110000],b[110000]; void bfs(int st) { int head=1,tail=2;list[1]=st; while(head!=tail) { int x=list[head];head++; v[x]=true; for(int k=last[x];k;k=a[k].next)b[a[k].y]=true; for(int y=R[0];y<=n;y=R[y]) if(v[y]==false&&b[y]==false) R[L[y]]=R[y],L[R[y]]=L[y],list[tail++]=y; for(int k=last[x];k;k=a[k].next)b[a[k].y]=false; } as[++aslen]=tail-1; } int main() { int x,y; scanf("%d%d",&n,&m); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); ins(x,y),ins(y,x); } L[0]=0;R[0]=1; for(int i=1;i<=n;i++)L[i]=i-1,R[i]=i+1; L[n+1]=n;R[n+1]=n+1; memset(v,false,sizeof(v)); for(int i=1;i<=n;i++) if(v[i]==false)bfs(i); sort(as+1,as+aslen+1); printf("%d\n",aslen); for(int i=1;i<aslen;i++)printf("%d ",as[i]); printf("%d\n",as[aslen]); return 0; }
pain and happy in the cruel world.