【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();
}
posted @ 2018-12-03 13:24  Inspector_Javert  阅读(116)  评论(0编辑  收藏  举报