P5268 [SNOI2017]一个简单的询问 题解

Tarantula

2022-04-13 10:26:19

Solution

这里提供一个无脑分块做法。 看到数据范围 $5\times 10^4$,考虑分块,设块长为 $\sqrt n$。令 $sum_{i,j}$ 表示前 $j$ 个数对第 $i$ 个块产生的贡献。这个东西可以 $O(n\sqrt n)$ 预处理出来。 对于每个询问,把它拆成三个部分: - 区间二的所有整块 对 整个区间一 产生的贡献 - 区间一的所有整块 对 区间二的散块 产生的贡献 - 区间一的散块 对 区间二的散块 产生的贡献 建议自己画个图理解一下。 前两个部分显然可以直接利用 $sum$ 来搞,对于第三个部分,暴力开桶,扫一遍就没了。 时空复杂度均为 $O(n\sqrt n)$。常数较莫队略大,但不卡常也能做到稳定跑过。 ```cpp #include<bits/stdc++.h> using namespace std; const int maxn = 50005, maxb = 255; int n, m, block, t; int a[maxn], ind[maxn]; int sum[maxb][maxn]; int st[maxb], ed[maxb], pos[maxn]; int cnt[maxn]; void discrete() { memcpy(ind, a, sizeof(a)); sort(ind + 1, ind + 1 + n); int len = unique(ind + 1, ind + 1 + n) - ind - 1; for (int i = 1; i <= n; i++) a[i] = lower_bound(ind + 1, ind + 1 + n, a[i]) - ind; } void getsum(int k) { for (int i = st[k]; i <= ed[k]; i++) cnt[a[i]]++; for (int i = 1; i <= n; i++) sum[k][i] = sum[k][i - 1] + cnt[a[i]]; for (int i = st[k]; i <= ed[k]; i++) cnt[a[i]]--; } void init() { block = sqrt(n); t = ceil(n * 1. / block); for (int i = 1; i <= t; i++) { st[i] = (i - 1) * block + 1; ed[i] = min(i * block, n); for (int j = st[i]; j <= ed[i]; j++) pos[j] = i; } for (int i = 1; i <= t; i++) getsum(i); } int query(int l1, int r1, int l2, int r2) { int p1 = pos[l1], q1 = pos[r1], p2 = pos[l2], q2 = pos[r2], ans = 0; for (int i = p2 + 1; i <= q2 - 1; i++) ans += sum[i][r1] - sum[i][l1 - 1]; for (int i = p1 + 1; i <= q1 - 1; i++) if (p2 != q2) ans += sum[i][ed[p2]] - sum[i][l2 - 1] + sum[i][r2] - sum[i][st[q2] - 1]; else ans += sum[i][r2] - sum[i][l2 - 1]; if (p2 == q2) for (int i = l2; i <= r2; i++) cnt[a[i]]++; else { for (int i = l2; i <= ed[p2]; i++) cnt[a[i]]++; for (int i = st[q2]; i <= r2; i++) cnt[a[i]]++; } if (p1 == q1) for (int i = l1; i <= r1; i++) ans += cnt[a[i]]; else { for (int i = l1; i <= ed[p1]; i++) ans += cnt[a[i]]; for (int i = st[q1]; i <= r1; i++) ans += cnt[a[i]]; } if (p2 == q2) for (int i = l2; i <= r2; i++) cnt[a[i]]--; else { for (int i = l2; i <= ed[p2]; i++) cnt[a[i]]--; for (int i = st[q2]; i <= r2; i++) cnt[a[i]]--; } return ans; } int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; discrete(); init(); cin >> m; for (int i = 1; i <= m; i++) { int l1, r1, l2, r2; cin >> l1 >> r1 >> l2 >> r2; cout << query(l1, r1, l2, r2) << endl; } return 0; } ```