zoukankan      html  css  js  c++  java
  • UVA-11987-Almost Union-Find(并查集删除)

    I hope you know the beautiful Union-Find structure. In this problem, you're to implement something similar, but not identical.

    The data structure you need to write is also a collection of disjoint sets, supporting 3 operations:

    1 p q  Union the sets containing p and q. If p and q are already in the same set, ignore this command.

    2 p q  Move p to the set containing q. If p and q are already in the same set, ignore this command

    3 p     Return the number of elements and the sum of elements in the set containing p.

    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). The size of input file does not exceed 5MB.

    Output
    For each type-3 command, output 2 integers: the number of elements and the sum of elements.

    Sample Input
    5 7
    1 1 2
    2 3 4
    1 3 5
    3 4
    2 4 1
    3 4x
    3 3
    Output for the Sample Input
    3 12
    3 7
    2 8
    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}


    思路:并查集删除。被删除的节点的关系不能在原集合里删除,因为其子节点需要它来和爷爷节点联系。通过建立虚拟节点。

    在没删除之前的操作就用id[x]代替x。如果有删除操作,之后对x的操作就是在对id[x]进行操作。

    PS:真正的并查集删除操作是不存在的,建立虚拟编号相当于克隆了一个“被删除”的节点,原来的集合里还是存在“被删除”的节点的。只是以后只调用编号了而不会调用真正的节点本身。


    #include<cstdio>
    using namespace std;
    int pre[200005],num[200005],sum[200005],id[100005];//id为虚拟编号节点 
    int n,m,l;
    
    void init(){
        l=n;
        for(int i=0;i<=n;i++){
            sum[i]=pre[i]=id[i]=i;
            num[i]=1;        
        }
    } 
    
    int find(int x){
        while(pre[x]!=x){
            int r=pre[x];
            pre[x]=pre[r];
            x=r;
        }
        return x;
    }
    
    void merge(int x,int y){
        int fx=find(x);
        int fy=find(y);
        if(fx!=fy)     {
        pre[fx]=fy;
        num[fy]+=num[fx];
        sum[fy]+=sum[fx];
        }
    }
    
    void move(int x){
        int fx=find(id[x]);// 移走后id[x]被更新,但pre[x]不能被更新,要保留,所以只能用虚拟节点! 
        sum[fx]-=x;            
        num[fx]--;             
        id[x]=++l; //x是第l-n个被删除的节点 
        sum[id[x]]=x;
        num[id[x]]=1;
        pre[id[x]]=id[x];
    }
    
    int main(){
        int d,p,q;
        while(~scanf("%d%d",&n,&m)){
            init();    
            while(m--){
                scanf("%d%d",&d,&p);
                if(d==1){
                    scanf("%d",&q);
                    merge(id[p],id[q]);
                }
                 else if(d==2){
                    scanf("%d",&q);
                    if(find(id[p])!=find(id[q])){            
                        move(p); 
                        merge(id[p],id[q]);        
                     }
                }
                else{
                    int fp=find(id[p]);
                    printf("%d %d
    ",num[fp],sum[fp]);
                }
            }    
        }
        return 0;
    } 

  • 相关阅读:
    12.4
    12.3
    学期总结
    12.20 期末考试总结
    12.18 准备
    12.17 CSS学习
    12.16 CSS学习
    12.15 CSS学习
    12.14 学习总结
    12.11 AJAX的基础知识
  • 原文地址:https://www.cnblogs.com/yzhhh/p/9969060.html
Copyright © 2011-2022 走看看