其他分享
首页 > 其他分享> > [FJOI2015]火星商店问题(线段树分治+可持久化01trie树)

[FJOI2015]火星商店问题(线段树分治+可持久化01trie树)

作者:互联网

题目:洛谷P4585

题目描述:

有\(n\)个商店,每个商店初始都有一种特殊物品,你可以在任意时间购买,在某个时间点会出现某种物品可以在某种商店中购买,所有的物品都有一个价格\(val\),每种物品都有无限多个

多个询问,每个询问为在当前那个时间点,询问一个\((l,r,x,d)\),必须购买且仅能购买一件物品,购买的物品只能在商店\([l,r]\)中,且购买的物品要么是特殊物品,要么就是出现时间一直到现在(包括现在的时间)一共最多为\(d\)天,求能得到的最大异或值\(x \bigotimes val\)

添加物品和询问答案都为操作数\(m\)的一部分

\(n,m,x,val \leq 100000\),\(1 \leq l,r \leq n\)

蒟蒻题解:

没怎么做过线段树分治,写道题来加深点印象

特殊物品和后面出现的物品可以分开算,两边取\(max\),特殊物品只要可持久化\(01trie\)做一下就好了,这里不详细展开

只考虑后面出现的物品

这题有时间和位置两个限制,每件物品出现的时间已知,消失时间为最后时间点(或者说永远也不会消失)

方法一:线段树套\(01trie\)树,对于位置区间,用线段树来处理,又因为每个物品都不会消失,所以对于一个线段树所套的\(01trie\)树,记录最后一次出现的点就可以处理时间的限制,可以实现强制在线,时空复杂度均为\(\Theta(nlog^{2}n)\)

方法二:线段树分治+可持久化\(01trie\)树,由于这题可以离线做,且它有时间、空间双重限制,考虑用线段树分治解决时间限制,将询问拆成多个,那么对于空间限制,可以把操作按位置排序,只要在每个线段树上的节点按位置建可持久化\(01trie\)树,下传操作时再按时间分成两类下传,时间复杂度\(\Theta(nlog^{2}n)\),空间复杂度\(\Theta(nlog\ n)\),在空间上比树套树做法优掉了一个\(log\),以下的代码为方法二的代码

参考程序:

#include<bits/stdc++.h>
using namespace std;
#define Re register int

const int N = 100005, M = 1800005;
struct infm
{
	int id, s, t;
}a[N], g1[N], g2[N];
struct infq
{
	int l, r, tl, tr, s;
}qu[N];
int n, m, num, tim, resm, resq, res, cnt1, cnt2, d[N], rt[N], ans[N], son[M][2];
vector<int> vt[N << 2];

inline int read()
{
	char c = getchar();
	int ans = 0;
	while (c < 48 || c > 57) c = getchar();
	while (c >= 48 && c <= 57) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
	return ans;
}

inline void write(int x)
{
	int num = 0;
	char sc[15];
	if (!x) sc[num = 1] = 48;
	while (x) sc[++num] = x % 10 + 48, x /= 10;
	while (num) putchar(sc[num--]);
	putchar('\n');
}

inline int max(int x, int y)
{
	return x > y ? x : y;
}

inline int ins(int id, int x, int y)
{
	int z = ++num;
	son[z][0] = son[z][1] = 0;
	if (x < 0) return z;
	bool t = (y >> x) & 1;
	son[z][t] = ins(son[id][t], x - 1, y), son[z][t ^ 1] = son[id][t ^ 1];
	return z;
}

inline int que(int id1, int id2, int x, int y)
{
	if (x < 0) return 0;
	bool t = ((y >> x) & 1) ^ 1;
	if (son[id1][t] ^ son[id2][t]) return (1 << x) | que(son[id1][t], son[id2][t], x - 1, y);
	else return que(son[id1][t ^ 1], son[id2][t ^ 1], x - 1, y);
}

inline void upd(int id, int l, int r, int x, int y, int z)
{
	if (x <= l && r <= y)
	{
		vt[id].push_back(z);
		return;
	}
	int mid = l + r >> 1;
	if (x <= mid) upd(id << 1, l, mid, x, y, z);
	if (y > mid) upd(id << 1 | 1, mid + 1, r, x, y, z);
}

inline bool cmp(infm x, infm y)
{
	return x.id < y.id;
}

inline int find_id(int x)
{
	if (x < d[1]) return 0;
	if (x >= d[res]) return res;
	int l = 2, r = res - 1, s = 1;
	while (l <= r)
	{
		int mid = l + r >> 1;
		if (d[mid] <= x) s = mid, l = mid + 1;
		else r = mid - 1;
	}
	return s;
}

inline void dfs(int id, int l, int r, int x, int y)
{
	rt[1] = num = 0, d[res = 1] = a[x].id;
	for (Re i = x; i <= y; ++i)
	{
		if (a[i].id > d[res]) d[++res] = a[i].id, rt[res] = rt[res - 1];
		rt[res] = ins(rt[res], 16, a[i].s);
	}
	int u = vt[id].size();
	for (Re i = 0; i < u; ++i)
	{
		int v = vt[id][i];
		ans[v] = max(ans[v], que(rt[find_id(qu[v].l)], rt[find_id(qu[v].r)], 16, qu[v].s));
	}
	if (l == r) return;
	int mid = l + r >> 1, cnt1 = cnt2 = 0;
	for (Re i = x; i <= y; ++i)
		if (a[i].t <= mid) g1[++cnt1] = a[i];
		else g2[++cnt2] = a[i];
	for (Re i = x; i < x + cnt1; ++i) a[i] = g1[i - x + 1];
	for (Re i = x + cnt1; i <= y; ++i) a[i] = g2[i - x - cnt1 + 1];
	if (cnt1) dfs(id << 1, l, mid, x, x + cnt1 - 1);
	if (cnt2) dfs(id << 1 | 1, mid + 1, r, x + cnt1, y);
}

int main()
{
	n = read(), m = read();
	for (Re i = 1; i <= n; ++i) rt[i] = ins(rt[i - 1], 16, read());
	for (Re i = 0; i < m; ++i)
	{
		int opt = read();
		if (!i || !opt) ++tim;
		if (!opt)
		{
			int x = read(), y = read();
			a[++resm] = infm{x, y, tim};
		}
		else
		{
			int l = read() - 1, r = read(), x = read(), y = read();
			qu[++resq] = infq{l, r, max(tim - y + 1, 1), tim, x}, ans[resq] = que(rt[l], rt[r], 16, x);
		}
	}
	for (Re i = 1; i <= resq; ++i)
		if (qu[i].tl <= qu[i].tr) upd(1, 1, tim, qu[i].tl, qu[i].tr, i);
	sort(a + 1, a + resm, cmp);
	dfs(1, 1, tim, 1, resm);
	for (Re i = 1; i <= resq; ++i) write(ans[i]);
	return 0;
}

标签:rt,01trie,int,res,线段,son,物品,FJOI2015,id
来源: https://www.cnblogs.com/clfzs/p/14632874.html