zoukankan      html  css  js  c++  java
  • BZOJ_1015_[JSOI2008]星球大战_并查集

    BZOJ_1015_[JSOI2008]星球大战_并查集

    题意:很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系。某一天,凭着一个偶然的
    机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直
    接或间接地连接。 但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划
    地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。现在,反抗军首
    领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每
    一次打击之后反抗军占据的星球的连通快的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则
    这两个星球在同一个连通块中)。

    分析:离线,把删除当作插入,每次用并查集维护连通块个数。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 400050
    int n,fa[N],m,q[N],ans[N],cnt;
    int head[N],to[N<<1],nxt[N<<1],vis[N],k;
    inline void add(int u,int v)
    {
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;    
    }
    int find(int x)
    {
        int p=fa[x];
        while(p!=fa[p])p=fa[p];
        while(x!=p){
            int tmp=fa[x];
            fa[x]=p;
            x=tmp;    
        }
        return fa[x];    
    }
    int main()
    {
        register int i,j;
        int x,y;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)fa[i]=i;
        for(i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            x++,y++;
            add(x,y);add(y,x);
        }
        for(i=1;i<=n;i++)vis[i]=1;
        scanf("%d",&k);
        ans[k]=n-k;
        for(i=1;i<=k;i++){
            scanf("%d",&q[i]);
            q[i]++;
            vis[q[i]]=0;
        }
        for(i=1;i<=n;i++){
            if(!vis[i])continue;
            for(j=head[i];j;j=nxt[j]){
                if(!vis[to[j]])continue;
                int dj=find(to[j]),di=find(i);
                if(di!=dj){
                    fa[di]=dj;ans[k]--;
                }
            }
        }
        vis[q[k]]=1;
        for(i=k-1;i>=0;i--){
            int x=q[i+1];
            ans[i]=ans[i+1]+1;
            for(j=head[x];j;j=nxt[j]){
                int t=to[j];
                if(!vis[t])continue;
                int dy=find(t),dx=find(x);    
                if(dx!=dy){
                    fa[dy]=dx;ans[i]--;    
                }
            }
            vis[q[i]]=1;
        }
        for(i=0;i<=k;i++){
            printf("%d
    ",ans[i]);
        }
    }
    
  • 相关阅读:
    golang 数据结构 优先队列(堆)
    leetcode刷题笔记5210题 球会落何处
    leetcode刷题笔记5638题 吃苹果的最大数目
    leetcode刷题笔记5637题 判断字符串的两半是否相似
    剑指 Offer 28. 对称的二叉树
    剑指 Offer 27. 二叉树的镜像
    剑指 Offer 26. 树的子结构
    剑指 Offer 25. 合并两个排序的链表
    剑指 Offer 24. 反转链表
    剑指 Offer 22. 链表中倒数第k个节点
  • 原文地址:https://www.cnblogs.com/suika/p/8456917.html
Copyright © 2011-2022 走看看