NOJ[1508] 火烧赤壁2

来源:互联网 发布:java并发实战 编辑:程序博客网 时间:2024/04/20 09:39
  • 时间限制: 1000 ms 内存限制: 65535 K
  • 问题描述
  • 上次出了一道火烧赤壁的题目给当时的新生,也就是你们的上一届学长们做,那么这次,我又想到了另一个想法。
    上次的火烧赤壁的题号为1274
    这次稍微难一点,我们来个火烧赤壁2吧。

    Hungar个人很喜欢曹操这个人,所以这次有机会穿越到三国时代,他想帮助曹操打赢赤壁之战。
    但是他去晚了,当他穿越到那的时候发现大火已经在蔓延了,所以他能做的就是马上告诉曹操把已经着火的船的锁链(船与船相连都是靠锁链达到的)给破坏掉使火不会蔓延到附近的船只。

    现在告诉你曹操一共有N艘船,M条铁链,船只编号从0开始到n-1。
    然后再告诉你依次着火的船只编号,问舍弃那艘船以后,剩下的船只能形成几个连通块(只要是被铁链连在一起的全部船只,就算一共连通块)。
    船与船之间可能存在多条锁链。

  • 输入
  • 输入包括第一行两个整数,N(1 <= N <= 2M)和M(1 <= M <= 200,000)。
    接下来M行,每行包括两个整数x和y(x != y),分别表示编号为x和y的船只被一根锁链连起来。
    再接下来一个正整数T表示着火船只的数量。
    接下来T行,每行包含一个整数z表示被烧船只的编号,编号不会出现一样的,也就是说已经被烧的船只不会再去烧它。
  • 输出
  • 输出z+1个数,第一行为着火前这些船的连通块数,后z行表示每次依次烧掉一只船后,剩下的连通块数。
  • 样例输入
  • 8 130 11 66 55 00 61 22 33 44 57 17 27 63 6516357
  • 样例输出
  • 111233
  • 提示
  • 并查集
  • 来源
  • Hungar

用最朴素的做法,我们要建很多次图,时间上不允许,所以得想点什么优化,本弱刚看到也没什么头绪,后来听说要把操作保留,然后逆序操作,瞬间就折服了


我们先构建一张图,其中不包括烧掉的点和边,那么这就是最后的情况了,之后我们每次都添加被烧的那个点和附属的边。原来是去点,现在相当于从最后加点。


#include<stdio.h>#include<string.h>const int maxn=400010;int father[maxn];bool flag[maxn];int turn[maxn];int ans2[maxn]; struct node{int to;int next;}edge[maxn];int head[maxn];int tot,ans;void addedge(int from,int to){edge[tot].to=to;edge[tot].next=head[from];head[from]=tot++;}int find(int x){if(father[x]==-1)  return x;    return father[x]=find(father[x]);}void Union(int x,int y){int a=find(x);int b=find(y);if(a!=b){father[a]=b;ans--;}}int main(){int n,m;while(~scanf("%d%d",&n,&m)){memset(flag,0,sizeof(flag));memset(head,-1,sizeof(head));memset(father,-1,sizeof(father));tot=0;int x,y;for(int i=0;i<m;i++){scanf("%d%d",&x,&y);addedge(x,y);addedge(y,x);}        int t;        scanf("%d\n",&t);        ans=n-t;        for(int i=0;i<t;i++)        {      scanf("%d",&turn[i]);      flag[turn[i]]=1;        }        for(int i=0;i<n;i++)        {        if(flag[i])          continue;       for(int j=head[i];j!=-1;j=edge[j].next)       if(!flag[edge[j].to])           Union(i,edge[j].to);    //最后的情况时2个点都没被烧掉的才可以并         }        ans2[t]=ans;        for(int i=t-1;i>=0;i--)        {flag[turn[i]]=0;ans++;        for(int j=head[turn[i]];j!=-1;j=edge[j].next)        {         if(!flag[edge[j].to])        Union(turn[i],edge[j].to);        }    ans2[i]=ans;        }        for(int i=0;i<=t;i++)            printf("%d\n",ans2[i]);}return 0;}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信超额20万怎么办 微信支付超额了怎么办 微信零钱超额了怎么办 微信的充值冲错了怎么办 有流量还扣话费怎么办 自动取款机充值到电子账户怎么办 淘宝qb充错了怎么办 q币冲错了人家不给怎么办 qq充值话费错号怎么办 qq充错号码了怎么办 qq交话费不到账怎么办 充错手机号码而且是空号怎么办 微信钱包充错话费怎么办 QQ充值话费充到空号了怎么办 给别人充错话费怎么办 用qq交错话费对方是空号怎么办 号码变成空号了怎么办 qq冲流量冲错了怎么办 流量冲错了套餐怎么办 微信流量充错号码怎么办 微信支付不进账怎么办 充话费充不进去怎么办 用支付宝充话费没到账怎么办 支付宝充话费未到账怎么办 话费充了不到账怎么办 转转买家不确认收货怎么办 充话费错了怎么办啊 淘宝充值流量没到账怎么办 微信手机充错了怎么办 支付宝充话费没到账怎么办 裤子摔了一个洞怎么办 顾客反应衣服质量不好怎么办 淘宝买的衣服味道很大怎么办 三国杀账号忘了怎么办 宽带连接被删了 怎么办 手机被偷了qq怎么办 手机丢了微信怎么办啊 手机店把手机修坏了怎么办 在手机店买到山寨机手机怎么办 有人在qq群上骂我怎么办 qq群一直有人骚扰怎么办