并查集(删除) UVA 11987 Almost Union-Find

 

题目传送门

题意:训练指南P246

分析:主要是第二种操作难办,并查集如何支持删除操作?很巧妙的方法:将并查集树上p的影响消除,即在祖先上(sz--, sum -= p),然后为p换上马甲:id[p] = ++pos(可多次),这样id[p]就相当于是新的一个点,那么在Find(x)寻找祖先时要用x的马甲来寻找,即Find (id[x])。

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;
int rt[N], sz[N], sum[N], id[N/2];
int n, m;

void init()    {
    memset (rt, -1, sizeof (rt));
    for (int i=1; i<N; ++i) {
        sz[i] = 1;  sum[i] = i;
    }
    for (int i=1; i<=n; ++i)   id[i] = i;
}

int Find(int x) {
    return rt[x] == -1 ? x : rt[x] = Find (rt[x]);
}

int main(void)  {
    while (scanf ("%d%d", &n, &m) == 2) {
        init ();
        int op, p, q, pos = n;
        for (int i=1; i<=m; ++i)    {
            scanf ("%d%d", &op, &p);
            if (op == 3)    {
                int fp = Find (id[p]);
                printf ("%d %d\n", sz[fp], sum[fp]);
            }
            else    {
                scanf ("%d", &q);
                int fp = Find (id[p]), fq = Find (id[q]);
                if (op == 1)    {
                    if (fp != fq)   {
                        rt[fp] = fq;
                        sz[fq] += sz[fp];
                        sum[fq] += sum[fp];
                    }
                }
                else    {
                    if (fp != fq)   {
                        sz[fp]--;   sum[fp] -= p;
                        id[p] = ++pos;      //马甲!
                        rt[id[p]] = fq;
                        sz[fq]++;   sum[fq] += p;
                    }
                }
            }
        }
    }

    return 0;
}

  

posted @ 2016-01-14 16:16  Running_Time  阅读(208)  评论(0编辑  收藏  举报