uva 11987 带删除的并查集

来源:互联网 发布:网络用语奶是什么意思 编辑:程序博客网 时间:2024/05/22 06:20

Initially, the collection contains n sets: {1}, {2}, {3}, … , {n}.
Input
There are several test cases. Each test case begins with a line containing two integers n and m
(1 ≤ n, m ≤ 100, 000), the number of integers, and the number of commands. Each of the next m lines
contains a command. For every operation, 1 ≤ p, q ≤ n. The input is terminated by end-of-file (EOF).
Output
For each type-3 command, output 2 integers: the number of elements and the sum of elements.
Explanation
Initially: {1}, {2}, {3}, {4}, {5}
Collection after operation 1 1 2: {1,2}, {3}, {4}, {5}
Collection after operation 2 3 4: {1,2}, {3,4}, {5} (we omit the empty set that is produced when
taking out 3 from {3})
Collection after operation 1 3 5: {1,2}, {3,4,5}
Collection after operation 2 4 1: {1,2,4}, {3,5}
输入 1 a b 把a,b所在的集合合并
输入 2 a b 把b从b所在的旧集合移到a的集合中
输入 3 a 输出a所在集合的元素个数和这个集合的元素和

一开始想并查集能做吗 怎么这么像stl 最后发现还是并查集
思路,如何删除一个并查集里面的一个元素加到另一个并查集内,通过思考发现,旧的并查集如果移除的是一般的结点还好做,如果是根节点,出现群龙无首的情况是不行的,所以旧的集合里面的根节点 f[根节点]是不能改变的。那么改变什么才好,- -答案就是用一个新的数组 po 反应的是当前元素的根节点的最新位置,即移除后的位置。 所有的find和merge都用id数组来寻找根结点,而f永远指向的是根节点,那么删除的话虽然元素和减少了但是对根节点的指向是不会变化的 因为f[ ]没变,再用po创建一个大于n的新空间放这个单独的元素就好。
由于求的东西比较多,指向当前位置的用 数组po 指定的是最新的位置。
用sum数组求根的里存放的和来代表集合的和
用pre数组代表集合里面的个数。
用f求的是父节点和根 每一个集合,即使删除也有旧的集合保留。父节点依旧保留

#include <iostream>#include <cstdio>#include <map>#include <cstring>using namespace std;const int maxn=100100;int f[maxn];int sum[maxn];int pre[maxn];int po[maxn];int n,m;int find(int x){    return (x==f[x])?f[x]:f[x]=find(f[x]);}int init(){    for(int i=1;i<=n;i++)    {        f[i]=i;        sum[i]=i;        po[i]=i;        pre[i]=1;    }}void merge(int a,int b){    int p=find(a);    int q=find(b);    if(p!=q)    {        f[p]=q;        pre[q]+=pre[p];        sum[q]+=sum[p];    }}int main(){    while(cin>>n>>m)    {        init();        int yi=n;        for(int i=0;i<m;i++)        {            int op;            cin>>op;            if(op==1)            {                int a,b;                cin>>a>>b;                merge(po[a],po[b]);            }            if(op==2)            {                int a,b;                cin>>a>>b;                int p1=find(po[a]);                int p2=find(po[b]);                if(p1!=p2)                {                    int t=find(po[a]);                    sum[t]-=a;                    pre[t]--;                    po[a]=++yi;                    f[yi]=yi;                    pre[yi]=1;                    sum[yi]=a;                    merge(po[a],po[b]);                }            }            if(op==3)            {            int a;            cin>>a;            int p1=find(po[a]);            cout<<pre[p1]<<" "<<sum[p1]<<endl;            }        }    }}
0 0
原创粉丝点击