[链表] BZOJ1098: [POI2007]办公楼biu

本文介绍了一种高效算法来解决反图联通块的问题。通过使用链表存储图结构,并结合广度优先搜索(BFS),实现了O(n+m)的时间复杂度。文中详细解释了如何避免重复访问节点以减少计算成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

太菜了…这都不会…
就是求反图的联通块。就是每次挑一个边在反图bfs出一个块。
我们每次找反图边扩展,是找原图中和当前节点不直接相连的其他点。直接暴力会变成 n2
所以需要把访问过的点马上删去。可以用链表。
这样每个点就只访问一次了。复杂度 O(n+m)

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100005,maxe=4000005;
int n,m,ans[maxn];
int fir[maxn],nxt[maxe],son[maxe],tot;
void add(int x,int y){
    son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;
}
int vis[maxn],clk;
int L[maxn],R[maxn],tem[maxn];
void Del(int x){ R[L[x]]=R[x]; L[R[x]]=L[x]; }
queue<int> que;
void bfs(){
    int x=R[0]; Del(x); que.push(x); ans[++ans[0]]=1;
    while(!que.empty()){
        int x=que.front(); que.pop(); clk++;
        for(int j=fir[x];j;j=nxt[j]) vis[son[j]]=clk;
        tem[0]=0;
        for(int i=R[0];i!=n+1;i=R[i]) if(vis[i]!=clk){
            que.push(i); tem[++tem[0]]=i; ans[ans[0]]++;
        }
        for(int i=1;i<=tem[0];i++) Del(tem[i]);
    }
}
int main(){
    freopen("bzoj1098.in","r",stdin);
    freopen("bzoj1098.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y; scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    R[0]=1; for(int i=1;i<=n;i++) L[i]=i-1, R[i]=i+1; L[n+1]=n;
    while(R[0]!=n+1) bfs();
    sort(ans+1,ans+1+ans[0]); 
    printf("%d\n",ans[0]);
    for(int i=1;i<=ans[0];i++) printf("%d ",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值