• 带权并查集


    有一个划分为N列的星际战场,各列依次编号为1,2,…,N。

    有N艘战舰,也依次编号为1,2,…,N,其中第i号战舰处于第i列。

    有T条指令,每条指令格式为以下两种之一:

    1、M i j,表示让第i号战舰所在列的全部战舰保持原有顺序,接在第j号战舰所在列的尾部。

    2、C i j,表示询问第i号战舰与第j号战舰当前是否处于同一列中,如果在同一列中,它们之间间隔了多少艘战舰。

    现在需要你编写一个程序,处理一系列的指令。

    提交平台:https://www.acwing.com/problem/content/240/

    容易想到并查集,却无从下手。

    辛苦的查阅了一上午,总算理解了一点点。

    首先,我们用num数组记录节点离队头的长度,sumn数组记录节点所在队的总长度

    那么,合并函数join并不算难

    void join(int q,int w)
    {
        int f1=find(q),f2=find(w);
        pre[f1]=f2;//f1队接f2队后面
        num[f1]=sumn[f2];//f1到队首的总长度就是f2队伍的长度
        sumn[f2]+=sumn[f1];//f2后面放了f1的队伍 
        sumn[f1]=0; //f1没了 
    }

    这样一来,队头算是维护成功了,那find操作时那些原来不是队头的节点怎么办呢?以下都是重点

    int find(int x)
    {
        if(pre[x]==x)    return pre[x];
        int t1=pre[x],t2=find(pre[x]);//t1是父亲,t2是队头
        pre[x]=t2;
        num[x]+=num[t1];
        return t2;
    }

    因为压缩了路径
    所以这个点到父亲的距离加上新压缩路径中没有计算的点 
    更深层次的解释是,1-3接在了4-5的后面
    变成了4-5-1-2-3
    这个时候1是更新过的(在join函数中),num[1]=sumn[4]=2
    但是2和3并没有更新过,所以在压缩路径时 
    2的爸爸是1,所以 num [ 2 ] = num [ 2 ] +num [ 1 ] =1+2=3
    3的爸爸是1,所以num [ 3 ] = num [ 3 ] + num [ 2 ] = 2+2=4

    你可能想问,3的爸爸不是2吗?但是我们这是个递归函数,路径已经被压缩,3的爸爸已经变成了1

    #include <bits/stdc++.h>
    using namespace std;
    int l,r,pre[30009],n;
    int num[30009];//记录节点到队首的长度
    int sumn[30009];//记录节点所在队伍的总数
    int find(int x)
    {
        if(pre[x]==x)    return pre[x];
        int t1=pre[x],t2=find(pre[x]);//t1是父亲,t2是队头
        pre[x]=t2;
        num[x]+=num[t1];
        return t2;
    }
    //因为压缩了路径
    //所以这个点到父亲的距离加上新压缩路径中没有计算的点 
    //更深层次的解释是,1-3接在了4-5的后面
    //变成了4-5-1-2-3
    //这个时候1是更新过的(在join函数中),num[1]=sumn[4]=2
    //但是2和3并没有更新过,所以在压缩路径时 
    //2的爸爸是1,所以num[2]=num[2]+num[1]=1+2=3
    //3的爸爸是1,所以num[3]=num[3]+num[2]=2+2=4 
    void join(int q,int w)
    {
        int f1=find(q),f2=find(w);
        pre[f1]=f2;
        num[f1]=sumn[f2];//f1到队首的总长度就是f2队伍的长度
        sumn[f2]+=sumn[f1];//f2后面放了f1的队伍 
        sumn[f1]=0; //f1没了 
    }
    int main()
    {
        char s;
        int u,v;
        for(int i=1;i<=30000;i++)    pre[i]=i,sumn[i]=1;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>s>>u>>v;
            if(s=='M')    join(u,v);
            else
            {
                if(find(u)!=find(v))    cout<<-1<<endl;
                else    cout<<abs(num[u]-num[v])-1<<endl;
            }
        }
        return 0;
    }
    /*
    11
    M 2 1
    M 3 2
    M 5 4
    M 1 5
    C 4 3
    */
    View Code
  • 相关阅读:
    Single Threaded Execution
    多线程(第三天)
    多线程(第二天)
    IE中float:right单独一行
    web.xml配置
    java调用asmx的webservice
    跨域访问
    jsp页面导入jstl标签
    搜索dwr做即时聊天的时候看到的问题
    LigerUI tree在ie下显示不出来/LigerUI 控件在ie下错乱
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12462304.html
Copyright © 2020-2023  润新知