【BZOJ1483】[HNOI2009]梦幻布丁(平衡树启发式合并+并查集)

题目:

BZOJ1483

分析:

(这题码了一下午,码了近250行,但是意外跑的比本校各位神仙稍快,特写博客纪念)

首先能看出一个显然的结论:颜色段数只会变少不会变多。

我们考虑用并查集维护区间,对于每个区间维护它的起点和终点。建\(n\)棵平衡树,第\(i\)棵存颜色为\(i\)的区间。把\(x\)变成\(y\)时进行启发式合并,同时对于\(x\)上的每个结点\([a,b]\),在\(y\)中找\(a-1\)\(b+1\)所在区间。如果存在则合并,并答案减\(1\);若不存在则向\(y\)中插入新结点。时间复杂度\(O(m\log ^2n)\)

代码:

代码不难写,就是长……

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
 
namespace zyt
{
    template<typename T>
    inline void read(T &x)
    {
        char c;
        bool f = false;
        x = 0;
        do
            c = getchar();
        while (c != '-' && !isdigit(c));
        if (c == '-')
            f = true, c = getchar();
        do
            x = x * 10 + c - '0', c = getchar();
        while (isdigit(c));
        if (f)
            x = -x;
    }
    template<typename T>
    inline void write(T x)
    {
        static char buf[20];
        char *pos = buf;
        if (x < 0)
            putchar('-'), x = -x;
        do
            *pos++ = x % 10 + '0';
        while (x /= 10);
        while (pos > buf)
            putchar(*--pos);
    }
    const int N = 1e6 + 10;
    int n, m, p[N], st[N], ed[N];
    int f(const int x)
    {
        return x == p[x] ? x : p[x] = f(p[x]);
    }
    int ans = 0;
    class Splay
    {
    private:
        struct node
        {
            int val, size;
            node *fa, *s[2];
            node(const int _val, node *_fa)
                : val(_val), fa(_fa)
            {
                size = 1;
                s[0] = s[1] = NULL;
            }
        }*head;
        bool dir(const node *rot)
        {
            return rot == rot->fa->s[1];
        }
        void update(node *rot)
        {
            rot->size = 1;
            if (rot->s[0])
                rot->size += rot->s[0]->size;
            if (rot->s[1])
                rot->size += rot->s[1]->size;
        }
        void rotate(node *rot)
        {
            node *f = rot->fa, *ff = f->fa;
            bool d = dir(rot);
            rot->fa = ff;
            if (ff)
                ff->s[dir(f)] = rot;
            else
                head = rot;
            f->s[d] = rot->s[!d];
            if (rot->s[!d])
                rot->s[!d]->fa = f;
            rot->s[!d] = f;
            f->fa = rot;
            update(f);
        }
        void splay(node *rot, const node *goal = NULL)
        {
            while (rot && rot->fa && rot->fa != goal)
            {
                node *f = rot->fa, *ff = f->fa;
                if (ff == goal)
                    rotate(rot);
                else if (dir(rot) ^ dir(f))
                    rotate(rot), rotate(rot);
                else
                    rotate(f), rotate(rot);
            }
            update(rot);
        }
        void del(node *rot, Splay &s)
        {
            if (!rot)
                return;
            int x = f(rot->val);
            bool flag = false;
            if (st[x] > 1 && s.find(f(st[x] - 1)))
            {
                p[x] = f(st[x] - 1);
                ed[f(st[x] - 1)] = ed[x];
                --ans, flag = true;
            }
            x = f(x);
            if (ed[x] < n && s.find(f(ed[x] + 1)))
            {
                p[x] = f(ed[x] + 1);
                st[f(ed[x] + 1)] = st[x];
                --ans, flag = true;
            }
            if (!flag)
                s.insert(rot->val);
            if (rot->s[0])
                del(rot->s[0], s);
            if (rot->s[1])
                del(rot->s[1], s);
            delete rot;
        }
        node *find(const int val)
        {
            node *rot = head;
            while (1)
            {
                if (!rot || rot->val == val)
                    return rot;
                if (val < rot->val)
                    rot = rot->s[0];
                else
                    rot = rot->s[1];
            }
        }
    public:
        void insert(const int val)
        {
            if (!head)
            {
                head = new node(val, NULL);
                return;
            }
            node *rot = head;
            while (1)
            {
                if (val < rot->val)
                {
                    if (rot->s[0])
                        rot = rot->s[0];
                    else
                    {
                        rot->s[0] = new node(val, rot);
                        splay(rot->s[0]);
                        break;
                    }
                }
                else
                {
                    if (rot->s[1])
                        rot = rot->s[1];
                    else
                    {
                        rot->s[1] = new node(val, rot);
                        splay(rot->s[1]);
                        break;
                    }
                }
            }
        }
        size_t size()
        {
            if (head)
                return head->size;
            else
                return 0;
        }
        friend void merge(Splay &a, Splay &b);
    }tree[N];
    inline void merge(Splay &a, Splay &b)
    {
        if (a.size() < b.size())
            swap(a, b);
        b.del(b.head, a);
        b.head = NULL;
    }
    int arr[N], tmp[N];
    int work()
    {
        read(n), read(m);
        int last = 1;
        for (int i = 1; i <= n; i++)
            read(arr[i]);
        p[1] = st[1] = ed[1] = 1;
        for (int i = 2; i <= n; i++)
        {
            if (arr[i] != arr[i - 1])
            {
                tree[arr[i - 1]].insert(last);
                st[i] = last = i, ++ans;
            }
            p[i] = last;
            ed[last] = i;
        }
        tree[arr[n]].insert(last), ++ans;
        while (m--)
        {
            int opt;
            read(opt);
            if (opt == 1)
            {
                int x, y;
                read(x), read(y);
                if (x != y)
                    merge(tree[y], tree[x]);
            }
            else
                write(ans), putchar('\n');
        }
        return 0;
    }
}
int main()
{
    return zyt::work();
}

猜你喜欢

转载自www.cnblogs.com/zyt1253679098/p/10057921.html