• 并查集


    感谢cyanigence-oi大佬(Orz)的题单

    模板 

    并查集 模板题

    预处理过程:void pre(),赋值数组a

    假设自己就是祖先,则用for循环,来储存每个父亲节点的值

    void pre()
    {
        for(int i=1;i<=n;i++) a[i]=i;
    }

    查询过程:int find(int k)

    用递归的形式一层一层的探索自己的祖先,根节点表示的就是祖先,判断两个人是不是同一个祖先,只要查询各自的根节点是否相同即可

    int find(int k)
    {
        if(a[k]==k) return k;
        else return a[k]=a[find(k)];
    }

    合并过程:void merge(int u,int v)

    void merge(int u,int v)
    {
        a[find(u)]=find(v);
    }

    按秩合并

    P1551 亲戚

    #include <bits/stdc++.h>
    using namespace std ;
    typedef long long ll;
    const int maxn = 2e5 + 10;
    typedef long long ll;
    ll n,m,p;
    int a[maxn];
    void pre()    //预处理
    {
        for(ll i=1;i<=n;i++)
        {
            a[i]=i;
        }
    }
    ll find(ll k)    //查询+路径压缩
    {
        if(a[k]==k) return k;
        else return a[k]=find(a[k]);
    }
    void merge1(ll u,ll v)    //合并路径
    {
        a[find(u)]=find(v);
    }
    int main()
    {
        scanf("%lld%lld%lld",&n,&m,&p);
        pre();
        ll x,y;
        for(ll i=1;i<=m;i++)
        {
            scanf("%lld%lld",&x,&y);
            merge1(x,y);
        }
        for(ll i=1;i<=p;i++)
        {
            scanf("%lld%lld",&x,&y);
            if(find(x)==find(y))
                printf("Yes
    ");
            else
                printf("No
    ");
        }
    }

    P2814 家谱

      用标准库的map

    #include <bits/stdc++.h>
    using namespace std;
    map<string,string>p;
    string find(string x)
    {
        if(p[x]==x) return x;
        else return p[x]=find(p[x]);
    }
    int main()
    {
        string sss,ss;
        char c;
        while(1)
        {
            scanf("%c",&c);
            if(c=='$')
                break;
            else if(c=='#')
            {
                cin>>ss;
                if(p[ss]=="")
                    p[ss]=ss;
            }
            else if(c=='?')
            {
                cin>>sss;
                cout<<sss<<" "<<find(sss)<<endl;
            }
            else if(c=='+')
            {
                cin>>sss;
                p[sss]=ss;
            }
        }
    }

    P1536 村村通

     找查两两村是否联通,即是否为同一个祖先,变量s作为记录连通块中的边数,因为并不是每个村和其他的村庄都是联通的,有可能存在鼓励的村庄。

    #include <bits/stdc++.h>
    using namespace std ;
    typedef long long ll;
    const ll maxn=2e5+10;;
    ll n,m,a[maxn];
    inline void pre()
    {
        for(ll i=1; i<=n; i++)
        {
            a[i]=i;
        }
    }
    inline ll find(ll k)
    {
        if(a[k]!=k) a[k]=find(a[k]);
        return a[k];
    
    }
    void merge(ll u,ll v)
    {
        a[find(u)]=find(v);
    }
    int main()
    {
        while(1)
        {
            ll f;
            scanf("%lld",&f);
            n=f;
            if(f==0) return 0;
            pre();
            scanf("%lld",&m);
            ll s=0;
            for(ll i=1; i<=m; i++)
            {
                ll x,y;
                scanf("%lld%lld",&x,&y);
                merge(x,y);
            }
            for(ll i=1; i<=n; i++)
            {
                if(a[i]==i)
                {
                    s++;
                }
            }
            cout<<s-1<<endl;
        }
    }

    P1396 营救

     创建结构体,存入u,v,w,对拥挤度w进行升序排序;

    并查集,当查询到s和t连通时,输出当前的最大拥挤度,由于之前已经有过升序排序的操作,这时候的最大拥挤度是最小的。

    #include <bits/stdc++.h>
    using namespace std ;
    typedef long long ll;
    const ll maxn=2e5+10;
    struct node
    {
        ll u,v,w;
    }way[maxn];
    inline bool cmp(node a,node b)
    {
        return a.w<b.w;
    }
    ll n,m,s,t;
    ll a[maxn];
    void pre()
    {
        for(ll i=0;i<maxn;i++)
        {
            a[i]=i;
        }
    }
    inline ll find(ll k)
    {
        if(a[k]!=k)
        {
            a[k]=find(a[k]);
        }
        return a[k];
    }
    inline void merge(ll uu,ll vv)
    {
        ll uuu=find(uu),vvv=find(vv);
        if(a[uuu]!=vvv)
            a[uuu]=vvv;
    }
    int main()
    {
        scanf("%lld%lld%lld%lld",&n,&m,&s,&t);
        pre();
        for(ll i=1;i<=m;i++)
        {
            scanf("%lld%lld%lld",&way[i].u,&way[i].v,&way[i].w);
        }
        sort(way+1,way+1+m,cmp);
        for(ll i=1;i<=m;i++)
        {
            merge(way[i].u,way[i].v);
            if(find(a[s])==find(a[t]))
            {
                printf("%lld
    ",way[i].w);
                break;
            }
        }
    }

    P1621 集合

    P4185 [USACO18JAN]MooTube

    P1197 [JSOI2008]星球大战

    bzoj2054疯狂的馒头

    P2294 [HNOI2005]狡猾的商人

    P1892 [BOI2003]团伙

    Interesting Computer Game   2020牛客暑期多校训练营(第八场)

    #include <bits/stdc++.h>
    #define T int t ;cin >> t;while(t--)
    using namespace std ;
    typedef long long ll;
    const int maxn = 2e5 + 10;
    ll vis[maxn],a[maxn],b[maxn],c[maxn],pre[maxn];
    //vis数组表示的是当前的节点是否被访问过
    //pre数组表示的是合并路径
    inline ll find(ll x)
    {
        return (x==pre[x]) ? x:pre[x]=find(pre[x]);
    }
    inline void merge(ll u,ll v)
    {
        ll x=find(u),y=find(v);
        if(x==y)
        {
            vis[x]=1;
            return;
        }
        pre[x]=y;//表示x,y的祖宗合并,即两者为同一祖先
        if(vis[x])vis[y]=1;//该节点表示已被访问
    }
    int main()
    {
        ll total=0;//用于输出Case情况的个数
        T
        {
            total++;
            ll n;
            ll tot=0;//tot表示存入数的个数
            scanf("%lld",&n);
            for(ll i=1; i<=n; i++)
            {
                scanf("%lld%lld",&a[i],&b[i]);
                c[++tot]=a[i];//c数组用于存放每个数字,方便接下去排序和去重,假设a和b的值完全不一样,那么c数组的大小需要两倍空间,即2e5+5
                c[++tot]=b[i];
            }
            for(ll i=0; i<=maxn; i++)//初始化操作
            {
                vis[i]=0;
                pre[i]=i;
            }
            sort(c+1,c+tot+1);//升序排序,便于接下来的去重
            int cnt=unique(c+1,c+tot+1)-(c+1);//去重,方便编号
            for(ll i=1; i<=n; i++)
            {
                a[i]=lower_bound(c+1,c+tot+1,a[i])-c;
    //从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,
    //找到返回该数字的地址,不存在则返回end。
    //通过返回的地址减去起始地址begin,得到找到数字在数组中的下标,下标即树的度数
                b[i]=lower_bound(c+1,c+tot+1,b[i])-c;
                merge(a[i],b[i]);//用下标代替实际数字,防止数组存不下
            }
            int ans=tot;
            for(ll i=1; i<=tot; i++)
            {
                if(pre[i]==i&&!vis[i])ans--;//根据《离散数学》相关知识,如果非连通块则ans减一
            }
            cout<<"Case #"<<total<<": "<<ans<<endl;
        }
    }

     P3958 奶酪

     被scy修改过的删边问题

    贪心题

    只要保证连通,即只要从树根节点到达叶子节点,变成初级通路(每个点只经过一次,边数=点数-1),不必构成回路,结果等于原始总边数(m)-初级通路(n-1)

    #include <bits/stdc++.h>
    using namespace std ;
    int main()
    {
        int a,b;
        cin>>a>>b;
        int bb=b;
        while(b--){int x;cin>>x>>x;}
        printf("%d
    ",bb-a+1);
    }

     家族

    查找连通块的个数,如果a[i]==i,则s++,s变量统计的就是连通块的个数。

    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    const ll maxn=1e5+10;
    ll a[maxn];
    void pre()
    {
        for(ll i=1;i<maxn;i++)
        {
            a[i]=i;
        }
    }
    inline ll find(ll k)
    {
        if(a[k]==k)
        {
            return a[k];
        }
        else
        {
            return a[k]=find(a[k]);
        }
    }
    inline void merge(ll u,ll v)
    {
        a[find(u)]=find(v);
    }
    ll n,m;
    int main()
    {
        scanf("%lld%lld",&n,&m);
        pre();
        ll x,y;
        for(ll i=1;i<=m;i++)
        {
            scanf("%lld%lld",&x,&y);
            merge(x,y);
        }
        ll s=0;
        for(ll i=1;i<=n;i++)
        {
            if(a[i]==i)
                s++;
        }
        cout<<s<<endl;
    }
  • 相关阅读:
    一个简单XQuery查询的例子
    《Microsoft Sql server 2008 Internals》读书笔记第七章Special Storage(1)
    《Microsoft Sql server 2008 Internals》读书笔记第八章The Query Optimizer(4)
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(4)
    SQL Server中SMO备份数据库进度条不显示?
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(5)
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(3)
    《Microsoft Sql server 2008 Internal》读书笔记第八章The Query Optimizer(2)
    省市三级联动的DropDownList+Ajax的三种框架(aspnet/Jquery/ExtJs)示例
    FireFox意外崩溃时的手工恢复命令
  • 原文地址:https://www.cnblogs.com/jackwang-sparrow/p/13419527.html
Copyright © 2020-2023  润新知