zoukankan      html  css  js  c++  java
  • 带逆向思维的并查集

    有一类并查集题目中,起始是一张连了所有边的图。

    给出一些操作,让一些边"断裂",再抛出一些问题。

    这个时候,就可以考虑逆向合并边。


    例题星球大战:https://www.luogu.com.cn/problem/P1197

    思路:

      因为每次轰炸星球,相当于把一个点完全抹除,相应的边也没了。

      那么我们完全可以先读入要摧毁的点,标记起来,然后在剩余的边里面

      挑出一些没有被摧毁的先建边。很神奇的,我们发现这个时候的连通块个数就是最后一次的个数

      那我们再把最后一个被摧毁的点相应的边连起来,再看看连通块个数,这个答案就是倒数第二次的答案

    不过要清楚一点。图中7和1起始也有边,但是我们从后逆推,那么1,3,5是已经被摧毁了的,所以我们暂时不能连边

    还有一点,每次我们连完了一个点对应的边,就要把它的标记清楚。因为再往前逆推,那么这个点其实是没有被摧毁的

    然后每次连接完一个点后,当前连通块个数都要+1

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=400009;
    struct node{
        int to,nxt;
    }d[maxn*2];
    int head[maxn*2],cnt=1,pre[maxn],n,m,q;
    void add(int u,int v){
        d[cnt].to=v,d[cnt].nxt=head[u],head[u]=cnt++;
    }
    int find(int x){
        if(x!=pre[x])    pre[x]=find(pre[x]);
        return pre[x];
    }
    void join(int q,int w){
        pre[find(q)]=find(w);
    }
    int vis[maxn],a[maxn],ans[maxn],ww;
    void init()
    {
        for(int i=1;i<=n;i++)
        {
            if(vis[i])    continue;//被摧毁的星球不连边
            for(int j=head[i];j;j=d[j].nxt)
            {
                if(vis[d[j].to])    continue;
                if(find(d[j].to)!=find(i))
                    ww--,join(d[j].to,i);    
            } 
        }
    }
    int main()
    {
        cin>>n>>m;
        for(int i=0;i<=n-1;i++)    pre[i]=i;
        for(int i=1;i<=m;i++)
        {
            int l,r;
            cin>>l>>r;
            add(l,r);add(r,l);
        }
        cin>>q;
        ww=n-q;
        for(int i=1;i<=q;i++)
        {
            int x;cin>>x;
            vis[x]=1;a[i]=x;
        }
        init();//连初始边 
        for(int i=q;i>=1;i--)
        {
            ans[i]=ww;
            for(int k=head[a[i]];k;k=d[k].nxt)
            {
                int z=d[k].to;
                if(vis[z])    continue;
                if(find(z)!=find(a[i]))
                    ww--,join(z,a[i]);
            }
            vis[a[i]]=0;
            ww++;//连通块个数加一 
        }
        cout<<ww<<endl;
        for(int i=1;i<=q;i++)    cout<<ans[i]<<endl;
    } 
  • 相关阅读:
    如何使用PhoneGap打包Web App
    js获取鼠标点击事件的相对位置
    IDEA跳转到上一个下一个方法的快捷键
    JunitGenerator
    无所不能的PowerMock,mock私有方法,静态方法,测试私有方法,final类
    IntelliJ IDEA 2019.3注册码(亲测有效,可激活至 2089 年)
    NACOS MalformedInputException 无法读取中文配置问题
    maven maven-surefire-plugin的乱码问题
    Idea单元测试Junit Generator设置
    Intellij IDEA中Mybatis Mapper自动注入警告的6种解决方案
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12468792.html
Copyright © 2011-2022 走看看