zoukankan      html  css  js  c++  java
  • P1197 [JSOI2008]星球大战

    -------------------------------------

    这可真是星球大战

    --------------------------------------

    链接: P1197

    -----------------------------------------

    看一下这道题,如果我们正着做,每摧毁一个后就重新建图,判连通。这样肯定工程浩大且超时,我们就要换个方法了。

    为什么不倒着做呢?我们先求出来最后剩下的数量,然后倒着恢复一个又一个的星球,并且重新判断这个星球的连通状况。

    欸,这样好像简单了许多

    ----------------------------------------

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 int n,m,k;
     7 const int maxn = 400010;
     8 int fa[maxn];//并查集判连通 
     9 int p;
    10 int head[maxn];
    11 int planet[maxn];//第i次炸了哪个星球 
    12 int ans[maxn];
    13 struct l{
    14     int from;
    15     int to;
    16     int next;
    17 }b[maxn];
    18 int x,y;
    19  void build(int f,int t){
    20     p++;
    21     b[p].next=head[f];
    22     b[p].from=f;
    23     b[p].to=t;
    24     head[f]=p;
    25 }//链表存图 
    26 inline int find(int x){
    27     if(fa[x]==x)
    28     return x;
    29     else
    30     return fa[x]=find(fa[x]);//查询
    31     //路径压缩 
    32 }
    33 bool boom[maxn];//是否已经被炸 
    34 int main(){
    35     scanf("%d%d",&n,&m);
    36     for(int i=0;i<=n;++i){
    37         fa[i]=i;
    38         head[i]=-1;//注意,有0号星球 
    39     }
    40     for(int i=1;i<=m;++i){
    41         scanf("%d%d",&x,&y);
    42 
    43         build(x,y);
    44         build(y,x);//无向图 
    45     }
    46     scanf("%d",&k);
    47     for(int i=1;i<=k;++i){
    48         scanf("%d",&planet[i]);
    49         boom[planet[i]]=1;//记录被炸的星球和什么时候被炸 
    50     }
    51     int le=n-k;//在全部炸完后的剩余 
    52     //我们假设全部都是不连通 
    53     for(int i=1;i<=2*m;++i){
    54         if((!boom[b[i].from])&&(!boom[b[i].to])&&(find(b[i].from)!=find(b[i].to)))
    55         {//如果两端没有被炸且不是已经联通 
    56             le--;//连通块减一 
    57             fa[find(b[i].from)]=fa[find(b[i].to)];
    58         }//检查联通,合并 
    59     }
    60     ans[k+1]=le;
    61     for(int t=k;t>=1;--t){//我们来逐渐修复 
    62         int u=planet[t];
    63         le++;//假定不连通 
    64         boom[u]=0;//恢复 
    65         for(int j=head[u];j!=-1;j=b[j].next){//遍历 
    66                 if(boom[b[j].to]==0&&(fa[find(u)]!=fa[find(b[j].to)]))//检查 
    67                 {
    68                     le--;//连通块减一,合并 AC
    69                     fa[find(b[j].to)]=fa[find(u)];
    70                 }
    71         }
    72         ans[t]=le;//统计这次后的数量 
    73     }
    74     for(int i=1;i<=k+1;++i)
    75     printf("%d
    ",ans[i]);//输出 
    76     return 0; 
    77 }
    AC
  • 相关阅读:
    JavaScript 学习笔记之最终篇
    JavaScript 学习笔记(三)
    JavaScript 学习笔记(一)
    JAVA 多线程机制(二)
    JAVA 多线程机制(一)
    apache配置CA证书通过https通信
    httpd的一些知识点
    Elasticsearch安装图形化界面工具Head插件
    Logstash收集nginx访问日志和错误日志
    lvm管理卷之缩减卷大小
  • 原文地址:https://www.cnblogs.com/For-Miku/p/11236505.html
Copyright © 2011-2022 走看看