可持久化数组的非可持久化线段树非可持久化平衡树实现(C++代码)

可持久化数组的非可持久化线段树非可持久化平衡树实现

  • 例题链接
  • 可持久化数组
    • 用满二叉树储存数组
    • 让二叉树可持久化
    • 时间复杂度
    • 空间复杂度
    • 模板代码
  • 例题分析与解决
    • 分析
      • 操作1
      • 操作2
    • 解决

例题链接

  洛谷P3919【模板】可持久化线段树 1(可持久化数组)

可持久化数组

用满二叉树储存数组

  首先给出二叉树节点的结构

struct Node
{
	T data;
	Node *left;
	Node *right;
};

  假设二叉树节点 p p p储存数组下标为的 i i i的值,则 p p p的左子节点储存数组下标为的 i ∗ 2 i * 2 i2的值, p p p的右子节点储存数组下标为的 i ∗ 2 + 1 i * 2 + 1 i2+1的值,这样数组就可以用二叉树储存.根节点储存数组下标为的 1 1 1的值。

让二叉树可持久化

  其实让二叉树可持久化的方法与让Trie树可持久化的方法是类似的,即被遍历的节点则复制原来的节点到新的节点,指向不遍历的节点的指针不变,指向遍历的节点的指针改为指向新节点。
假设有如下的二叉树(圆中所标为下标),可持久化数组的非可持久化线段树非可持久化平衡树实现(C++代码)_第1张图片
  改变下标为 6 6 6处的值(值未标出)后,二叉树结构如下
可持久化数组的非可持久化线段树非可持久化平衡树实现(C++代码)_第2张图片
  改变下标为 2 2 2处的值(值未标出)后,二叉树结构如下
可持久化数组的非可持久化线段树非可持久化平衡树实现(C++代码)_第3张图片

时间复杂度

   n n n表示数组大小, m m m表示操作次数。
  建立二叉树的时间复杂度为 O ( n ) O(n) O(n)。对于单次操作,最多遍历一条链上的节点,因此单次操作时间复杂度为 O ( log ⁡ 2 n ) O(\log_{2}{n}) O(log2n)。总时间复杂度为 O ( n + m ∗ log ⁡ 2 n ) O(n + m * \log_{2}{n}) O(n+mlog2n)

空间复杂度

   n n n表示数组大小, m m m表示操作次数。
  建立二叉树的空间复杂度为 O ( n ) O(n) O(n)。对于单次操作,最多复制一条链上的节点,因此单次操作空间复杂度为 O ( log ⁡ 2 n ) O(\log_{2}{n}) O(log2n)。总空间复杂度为 O ( n + m ∗ log ⁡ 2 n ) O(n + m * \log_{2}{n}) O(n+mlog2n)

模板代码

  下面给出已封装的可持久化数组的模板代码,注意数组下标从1开始,如果对时间要求不高可以去掉pool数组直接使用malloc或new分配内存,当然也可以自己实现一个更完善的内存池。
T数组储存的数据类型,maxTotalSize最多总共的(包括后续版本复制的)节点数,maxVersion最多版本数(0 ~ version - 1)。
  copyVersion完全复制一个历史版本并不做修改,changeVersion复制一个历史版本并修改对应数组下标处的值,setBasicVersion设置初始状态下的数组内容,注意数组应当从下标为1处开始储存。
  访问版本为version下标为index的值时可直接当做二维数组,即对象名[version][index]

template <typename T, int maxTotalSize, int maxVersion>
class DurableArray
{
	public:
		struct Node
		{
			T data;
			Node *left;
			Node *right;
		};
		static Node *getNode(Node *root, int index)
		{
			if (index == 1) return root;
			else
			{
				if (index & 1) return getNode(root, index / 2)->right;
				else return getNode(root, index / 2)->left;
			}
		}
		class DurableArrayRoot
		{
			private:
				friend class DurableArray;
				Node *root;
				DurableArrayRoot()
				{
					
				}
			public:
				T &operator [] (int index)
				{
					return getNode(root, index)->data;
				}
		};
	private:
		Node pool[maxTotalSize + 1];
		int allocated_size;
		Node *newNode()
		{
			allocated_size++;
			pool[allocated_size].left = NULL;
			pool[allocated_size].right = NULL;
			return &pool[allocated_size];
		}
		DurableArrayRoot roots[maxVersion];
		int versions;
	public:
		DurableArrayRoot &operator [] (int index)
		{
			return roots[index];
		}
		void setBasicVersion(int* datas, int size)
		{
			allocated_size = size + 1;
			for (int i = 1; i <= size; i++)
			{
				pool[i].data = datas[i];
				pool[i].left = (i * 2 > size) ? NULL : &pool[i * 2];
				pool[i].right = (i * 2 + 1 > size) ? NULL : &pool[i * 2 + 1];
			}
			roots[0].root = &pool[1];
			versions = 0;
		}
		void copyVersion(int oldversion)
		{
			roots[++versions].root = roots[oldversion].root;
		}
		void changeVersion(int oldversion, int index, T newData)
		{
			Node *new_root = newNode(), *p, *q;
			p = new_root;
			q = roots[oldversion].root;
			memcpy(p, roots[oldversion].root, sizeof(Node));
			bool seq[22];
			int max_height = 0, tmp = index;
			while (tmp > 1)
			{
				if (tmp & 1) seq[++max_height] = true;
				else seq[++max_height] = false;
				tmp >>= 1;
			}
			while (max_height)
			{
				if (seq[max_height])
				{
					p->right = newNode();
					memcpy(p->right, q->right, sizeof(Node));
					p = p->right;
					q = q->right;
				}
				else
				{
					p->left = newNode();
					memcpy(p->left, q->left, sizeof(Node));
					p = p->left;
					q = q->left;
				}
				max_height--;
			}
			p->data = newData;
			roots[++versions].root = new_root;
		}
};

class Qin
{
	public:
		Qin &operator >> (int &x)
		{
			int flag = 1;
			x = 0;
			char c;
			do
			{
				c = getchar();
			}
			while((c < '0' || c > '9') && c != '-');
			if (c == '-')
			{
				flag = -1;
				c = getchar();
			}
			while (c >= '0' && c <= '9')
			{
				x = x * 10 + c - '0';
				c = getchar();
			}
			x *= flag;
			return *this;
		}
};

例题分析与解决

分析

操作1

  操作1就是changeVersion

操作2

  操作2就是访问后再copyVersion

解决

这里只给出主函数,qin是我自己写的快速读入的类的实例化对象。

int main()
{
	int *base;
	int n, m;
	qin >> n >> m;
	base = new int[n + 1];
	for (register int i = 1; i <= n; i++) qin >> base[i];
	darray.setBasicVersion(base, n);
	delete[] base;
	while (m--)
	{
		int version, operation, index, value;
		qin >> version >> operation >> index;
		switch (operation)
		{
			case 1:
				qin >> value;
				darray.changeVersion(version, index, value);
				break;
			case 2:
				cout << darray[version][index] << endl;
				darray.copyVersion(version);
				break;
			default:
				;
		}
	}
	return 0;
}

你可能感兴趣的:(算法及数据结构,c++,算法)