CF1100F Ivan and Burgers

发布时间 2024-01-03 20:00:17作者: Schucking_Sattin

CF1100F Ivan and Burgers

Problem

给定一个长为 \(n\) 的序列,\(Q\) 查询区间异或最大值。

\(1 \le n, Q \le 5 \times 10^{5}\)

Solution 1

幸运数字的序列版本,但数据范围更大了,三只老哥很难冲得过去。

思考线段树和 ST 表的瓶颈,都是在于过多次数的线性基合并,所以我们的一种思路是优化线性基合并的次数。

这里考虑离线分治(整体二分)。

对于当前分治中心 \(mid\),处理出其向左的后缀线性基和向右的前缀线性基,然后对所有跨越 \(mid\) 的询问进行单次线性基合并。对于没有跨越 \(mid\) 的询问,递归下去解决。处理前后缀线性基的总时间复杂度为 \(O(n\log{n}\log{V})\),处理询问的时间复杂度为 \(O(Q\log^{2}{V})\)

code CF1100F - divide

Solution 2

有一个在线的两只老哥做法,没有用到线性基合并。

该做法在普通的异或线性基上,多记录了 取得基元素的位置

将原序列元素从左到右进行插入,得到 \(n\) 个前缀线性基,在插入过程中,不断将当前位置的元素在线性基中进行替换,使得取得基元素的位置尽量靠后。

查询区间 \([l, r]\) 时,使用第 \(r\) 个版本的线性基,从高位到低位考虑基元素,如果取得当前基元素的位置 \(\ge l\) 且异或上能使答案更优,则异或上该元素。

该贪心过程的正确性是:如果当前元素与线性基线性无关,则会增加线性基维数,不管如何插入,线性基的基元素位置集合都是一样的。

否则,此过程等价于枚举用当前元素替换掉某些基元素(能被替换掉的基元素集合 \(S\) 是确定的,可以证明插入过程可以考虑到集合 \(S\) 中的所有基元素),使得线性基张成的空间不变。这无疑可以使位置换到最优。

如果硬要解释《可以证明》,那我就开始胡言乱语了:

按最高位从大到小考虑基元素 \(\vec{v_{1}}, \vec{v_{2}}, \dots, \vec{v_{m}}\),记当前元素为 \(w\),并且钦定 \(w\)\((\vec{v_{1}}, \vec{v_{2}}, \dots, \vec{v_{m}})\) 线性相关。

如果一个基元素 \(\vec{v_{i}}\) 可以被 \(w\) 换出,等价于存在一组组合系数 \(a_{1}, \dots, a_{i - 1}, a_{i + 1}, \dots, a_{m}\),使得 \(\vec{v_{i}} = w \oplus \bigoplus\limits_{1 \le j \le m, i \neq j}a_{j}\vec{v_{j}}\)

先考虑 \(\vec{v_{1}}\),如果 \(w\)\(\vec{v_{1}}\) 对应的最高位为 \(1\),则 \(w\) 一定可以换出 \(\vec{v_{1}}\)。为什么?因为 \((\vec{v_{1}}, \vec{v_{2}}, \dots, \vec{v_{m}})\) 线性无关,把每个基元素对应一个维度,则 \(\vec{v_{1}}\) 对应的必然是最高位。将 \(\vec{v_{1}}\) 删除后,只会影响到最高位维度的消失;此时加入 \(w\),必然可以重新扩展最高位所在的维度,也只会影响到最高位所在的维度。反之,如果 \(w\)\(\vec{v_{1}}\) 对应的最高位为 \(0\),则 \(\vec{v_{1}}\) 的存在是必要的,不能被换出。

假设 \(\vec{v_{1}}\) 可以被 \(w\) 换出,如果要尝试表示出接下来的 \(\vec{v_{i}}\),则 \(a_{1}\) 必然为 \(1\),否则消不掉最高位,那么接下来一定不可能表示出 \(\vec{v_{i}}(i = 2, \dots, m)\)。但在实现上的解释略有不同:将线性基中的 \(\vec{v_{1}}\) 换成 \(w\),并把 \(w \oplus \vec{v_{1}}\) 作为接下来要插入的元素。这步操作在判定式上可以理解为:把 \(a_{1}\) 设置为 \(0\),并把 \(w\) 替换为 \(w \oplus \vec{v_{i}}\)

最终,所有能被 \(w\) 换出的基元素,都会被枚举一遍。选择其中位置最小的那个基元素换出即可,这也的确是最优的策略。

// Sea, You & Me
const int N = 5e5 + 5;
const int V = 20;
struct Linear_Base
{
	int b[V], pos[V];
	void clear()
	{
		for(int i = 0; i < V; ++i)
			b[i] = pos[i] = 0;
	}
	void insert(int x, int p)
	{
		for(int i = V - 1; i >= 0; --i)
			if(x & (1 << i))
			{
				if(!b[i]) return b[i] = x, pos[i] = p, void();
				else if(pos[i] < p) swap(pos[i], p), swap(b[i], x);
				x ^= b[i];
			}
	}
	int query_max(int l)
	{
		int res = 0;
		for(int i = V - 1; i >= 0; --i)
			if(b[i] && pos[i] >= l)
				chkmx(res, res ^ b[i]);
		return res;
	}
}LB[N];
int n, Q;
int main()
{
	read(n);
	LB[0].clear();
	for(int i = 1; i <= n; ++i)
	{
		LB[i] = LB[i - 1];
		int x; read(x);
		LB[i].insert(x, i);
	}
	read(Q);
	for(int cas = 1; cas <= Q; ++cas)
	{
		int l, r;
		read(l), read(r);
		printf("%d\n", LB[r].query_max(l));
	}
	return 0;
}

code CF1100F - on-line