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;
    } 
  • 相关阅读:
    符号解析
    编译器与链接器的功能
    hook的本质就是在本原可执行文件中加东西
    Mac-O文件加载的全过程(一)
    系统在执行可执行文件几个过程
    动态库连接器–动态库链接信息(Mach-O文件格式和程序从加载到执行过程)
    load 调用的顺序
    iPhone Mach-O文件格式与代码签名
    Redis正确使用的十个技巧
    redis slowlog
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12468792.html
Copyright © 2011-2022 走看看