我终将成为你的倒影:考察分块基本功的一道题。
注意到本题强制在线,且这种信息用线段树不是很好维护,所以可以很自然地想到分块。
又注意到 \(b \le 500\),所以考虑暴力枚举 \(b\)。发现当 \(b\) 固定的时候,\(a\) 取 \(a, a+b, a+2b\) 等数字答案是一样的,因为可以把分子中的 \(b\) 提出来,不会影响前后两个是否相等。于是可以把 \(\bm a\) 转化为 $ \bm{a\bmod b}$ 考虑。
因为将 \(a\) 对 \(b\) 取模了,所以此时 \(a< b \le 500\),容易想到一个暴力做法:将序列分块,每块维护 \(a, b\) 各自取值时的答案,查询的时候暴力查散块,整块直接加,两个块之间暴力计算,即可做到查询 \(O(\frac{n}{B})\),预处理 \(O(nb^2)\)。显然暴力预处理的部分只要把块数调小一点就不会 MLE,所以只需要优化预处理部分的时间复杂度即可。
继续观察这个函数的性质,因为所有数的 \(b\) 都是相等的,所以当两个数的函数值相差大于等于 \(\bm{2}\) 的时候,这两个数的函数值在任何时候都无法相等。因此枚举 \(b\) 之后,只需要考虑函数值相差 \(\bm1\) 的位置,根据 \(a\bmod b\) 的值分讨即可。具体而言,令 \(x = A_{i - 1} \bmod b, y = A_i \bmod b\):
- 当 \(A_{i - 1} = A_i\) 时,\(a\in[0, b)\)。
- 当 \(f(A_{i - 1}) = f(A_i)\) 时,\(a\in[0, b - \max\{x, y\})\cup[b - \min\{x, y\}, b)\)。
- 当 \(f(A_{i - 1}) = f(A_i) + 1, x < y\) 时,\(a\in[b - y, b - x)\)。
- 当 \(f(A_{i - 1})+1 = f(A_i) , x > y\) 时,\(a\in[b - x, b - y)\)。
- 其余情况 \(a\in \varnothing\)。
这样就可以 \(O(1)\) 计算 \(a\) 的区间了,做一个差分计算贡献即可。
总体时间复杂度 \(O(B+\frac{n}{B}+nb+\frac{n}{B}b^2)\)。当 \(\frac{n}{B} = B\) 时最优,因此 \(B = \sqrt n\)。但是因为此题卡空间,所以块长可能要调大一些。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 100005, M = 1005, MV = 105, V = 505;
int n, m, a[N];
struct Decompose{int B, Btot, L[M], R[M], bl[N];int val[MV][V][V];void build(){B = sqrt(n);Btot = (n + B - 1) / B;for(int i = 1; i <= Btot; i++){L[i] = (i - 1) * B + 1;R[i] = min(n, i * B);for(int j = L[i]; j <= R[i]; j++) bl[j] = i;}}void init(){for(int b = 1; b <= 500; b++){for(int i = 1; i <= Btot; i++){for(int j = L[i] + 1; j <= R[i]; j++){if(a[j] == a[j - 1]){val[i][b][0]++;continue;}if(abs(a[j] / b - a[j - 1] / b) >= 2) continue;int x = a[j - 1] % b, y = a[j] % b;if(a[j - 1] / b > a[j] / b){if(y > x){val[i][b][b - y]++;val[i][b][b - x]--;}}else if(a[j - 1] / b < a[j] / b){if(x > y){val[i][b][b - x]++;val[i][b][b - y]--;}}else{val[i][b][0]++;val[i][b][b - max(x, y)]--;val[i][b][b - min(x, y)]++;}}for(int j = 1; j < b; j++) val[i][b][j] += val[i][b][j - 1];}}}int query(int l, int r, int x, int y){int res = 0;if(bl[l] == bl[r]){for(int i = l + 1; i <= r; i++)res += ((a[i - 1] + x) / y == (a[i] + x) / y);return res;}for(int i = l + 1; i <= R[bl[l]]; i++)res += ((a[i - 1] + x) / y == (a[i] + x) / y);for(int i = L[bl[r]]; i <= r; i++)res += ((a[i - 1] + x) / y == (a[i] + x) / y);for(int i = bl[l] + 1; i < bl[r]; i++){res += val[i][y][x % y];res += ((a[L[i] - 1] + x) / y == (a[L[i]] + x) / y);}return res;}
}dc;
int main()
{//freopen("sample.in", "r", stdin);//freopen("sample.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m;for(int i = 1; i <= n; i++) cin >> a[i];dc.build();dc.init();int lastans = 0;for(int i = 1; i <= m; i++){int l, r, x, y;cin >> l >> r >> x >> y;l ^= lastans;r ^= lastans;x ^= lastans;y ^= lastans;lastans = dc.query(l, r, x, y);cout << lastans << "\n";}return 0;
}