【luogu P6466】分散层叠算法(Fractional Cascading)(二分)(模板)

分散层叠算法(Fractional Cascading)

题目链接:luogu P6466

题目大意

给你 k 个长度为 n 的有序数组,然后要你在线查询:
给你一个数 x,求每个数组 x 的非严格后继的异或和。

思路

首先考虑一些暴力之类的?
不难想到 \(O(nk\log n)\) 的二分暴力。

然后你考虑一个神奇的方法:
弄一个二维数组 \(B\),然后第 \(i\) 维除了放第 \(i\) 个有序数组,你还可以放第 \(i+1\) 维的数组中偶数位的部分。(这个可以归并排序实现)
这样有什么用呢?你会发现你如果求这个数组二分的答案,它原来的有序数组的答案其实可以用这个的答案在二分得到(而且其实就没有必要二分了,直接找后面第一个是原来有序数组的数,可以在归并排序的时候得到)。
然后你要求 \(i+1\) 的数组的答案的时候,你会发现你又像上面一样搞,位置的相差竟然至多是 \(1\)

然后你考虑你 \(B\) 数组每一维的数量,考虑每个的贡献,当前的是 \(1\),隔一个是 \(\dfrac{1}{2}\),然后 \(\dfrac{1}{4}\),所以总的来讲不到 \(2\)

然后你就可以 \(O(nk+q\log n+qk)\) 做了。


然后可以小小扩展一下,如果给定是一个图然后每个点有一个数列,度数不超过一个值 \(d\),每次询问是求图上一条链的每个点的答案。
那我们这里就是隔 \(d\) 个选一个,然后预处理的部分就是乘上一个 \(\log d\)

它其实有一个类似均摊的感觉,所以你可以和分块之类的结合起来,但是我就不会啦awa。
(不过你可以参考 IOI 2020 中国国家候选队论文《浅谈利用分散层叠算法对经典分块问题的优化》)

代码

#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 10000 + 10;
const int K = 100 + 10;
const int Q = 500000 + 10;
struct node {
	int x, nxt1, nxt2; 
}b[K][N << 1];
int n, k, q, d, lstans, sz[K], a[K][N], fir[N << 1], x;

int main() {
	scanf("%d %d %d %d", &n, &k, &q, &d);
	for (int i = 1; i <= k; i++)
		for (int j = 1; j <= n; j++) scanf("%d", &a[i][j]);
	
	sz[k] = n; for (int i = 1; i <= n; i++) b[k][i] = (node){a[k][i], i, 0};
	for (int i = k - 1; i >= 1; i--) {
		int x = 1, y = 2, nxt1 = 0, nxt2 = 0;
		while (x <= n && y <= sz[i + 1]) {
			if (a[i][x] < b[i + 1][y].x) nxt1 = x, b[i][++sz[i]] = (node){a[i][x], nxt1, nxt2 + 1}, x++;
				else nxt2 = y, b[i][++sz[i]] = (node){b[i + 1][y].x, nxt1 + 1, nxt2}, y = y + 2;
		}
		while (x <= n) nxt1 = x, b[i][++sz[i]] = (node){a[i][x], nxt1, nxt2 + 1}, x++;
		while (y <= sz[i + 1]) nxt2 = y, b[i][++sz[i]] = (node){b[i + 1][y].x, nxt1 + 1, nxt2}, y = y + 2;
	}
	for (int i = 1; i <= sz[1]; i++) fir[i] = b[1][i].x;
	
	for (int t = 1; t <= q; t++) {
		scanf("%d", &x); x ^= lstans;
		
		int p = lower_bound(fir + 1, fir + sz[1] + 1, x) - fir;
		lstans = 0;
		for (int i = 1; i <= k; i++) {
			while (p <= sz[i] && b[i][p].x < x) p++;
			while (p >= 2 && b[i][p - 1].x >= x) p--;
			if (p <= sz[i]) {
				lstans ^= a[i][b[i][p].nxt1];
				p = b[i][p].nxt2;
			}
			else p = sz[i + 1] + 1;
		}
		
		if (t % d == 0) {
			printf("%d\n", lstans);
		}
	}
	
	return 0;
}
posted @ 2022-03-18 20:44  あおいSakura  阅读(46)  评论(0编辑  收藏  举报