F-Frieza Frenzy

F-Frieza Frenzy SDU省赛团队排位赛(2)

https://codeforces.com/gym/324030/problem/F

弗里扎来到地球,正在寻找小悟空。
他没有那么耐心,所以他决定一条一条地摧毁道路,直到小悟空出现。
由于Frieza破坏了道路,一些地区的交通中断,一些地方的人们无法到达其他地方。如果从这个集合中的任何一个地方,可以到达它上面的每一个地方,而不可能到达它之外的任何地方,那么一组地方就被称为是连接的。
中心城市有n个地方和m条双向道路连接两个不同的地方。最初,城市是相连的。
小悟空一点也不在乎弗里扎,会让弗里扎毁掉所有的路。同时,他决定每次弗雷扎破坏一条道路时,都要计算中心城市中连接的地方的数量。你也不关心弗里扎,所以你会帮助小悟空。

输入
第一行输入包含两个整数,n和m(2≤n≤1e5,n−1≤m≤min(n×(n−1)/2e5)-中心城市的地方和道路数量。
接下来的m行包含两个整数ui和vi(1≤ui,vi≤n,ui≠vi)-第i条路连接的地方。
下一行包含m个数字,1到m之间的所有数字的排列-Frieza摧毁的道路序列。
对于每个u和v,保证只有一条路连接u和v。

输出
对于每一条被毁的道路,打印中心城市中连接的地方的数量。
——————————————————————————————
按顺序逐渐去除变可以转换成反序添加边。
如果某一次添加边把两个不连通的分量连在了一起。
那么就相当于去除之后多了一个连通分量。

所以反过来添加边,用并查集判断是否在同一个分块上。
如果在同一个分块,那么总分量等于添加前。
否则总分量等于添加前-1;

#include <bits/stdc++.h>
using namespace std;
struct edge{
    int u,v;
}e[100005];
int f[100005];
void init(){
    for(int i=0;i<=100000;i++){
        f[i]=i;
    }
}
int find(int x){
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}
int main(){
    init();
    int n,m;
    int ans[100005];
    int rmv[100005];
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>e[i].u>>e[i].v;
    }
    for(int i=1;i<=m;i++){
        cin>>rmv[i];
    }
    ans[m]=n;
    for(int i=m;i>=1;i--){
        int f1=find(e[rmv[i]].u);   //使用并查集时一定要先找到根节点
        int f2=find(e[rmv[i]].v);   //使用并查集时一定要先找到根节点
        if(f1==f2){
            ans[i-1]=ans[i];
        }else{
            ans[i-1]=ans[i]-1;
            f[f1]=f2;               //使用并查集时一定要先找到根节点
        }
    }
    for(int i=1;i<=m;i++){
        cout<<ans[i]<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值