CF1093E.Intersection of Permutations 题解 分块套树状数组
题目链接:https://codeforces.com/problemset/problem/1093/E
解题思路来自 oi.wiki
这道题 与其说是 “分块 套 树状数组”,不如说是 “树状数组 套 分块 (再)套 树状数组”。因为分块还需要用树状数组维护一个前缀和。
如果直接 分块 + 树状数组,时间复杂度是 \(O(m \sqrt{n} \log n)\),会超时。
如果再在分块外面维护一个树状数组,则时间复杂度降为 \(O(m \cdot ( \sqrt{n} + \log ( \sqrt{n} ) \log n ))\),可以通过本题。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5, maxb = sqrt(maxn) + 5;
int n, m, q, blo, N, tr[maxb][maxn], a[maxn], b[maxn], pa[maxn], pb[maxn];
int lowbit(int x) {
return x & -x;
}
int id(int p) {
return (p - 1) / blo + 1;
}
// 查询a[1..x] 有多少个数字在 b[1..y]
int query(int x, int y) {
// printf("\tquery (%-2d , %2d) = ", x, y);
int res = 0;
for (; x % blo; x--)
if (pb[a[x]] <= y)
res++;
if (!x) return res;
for (int i = id(x); i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
res += tr[i][j];
// cout << res << endl;
return res;
}
// 查询a[1..x] 有多少个数字在 b[l..r]
int query(int x, int l, int r) {
return query(x, r) - query(x, l-1);
}
// 查询a[l1..r1] 有多少个数字在 b[l2..r2]
int query(int l1, int r1, int l2, int r2) {
return query(r1, l2, r2) - query(l1-1, l2, r2);
}
// +1/-1(新增/解绑)a[x] -- b[y] 的关系
void add(int x, int y, int val) {
for (int i = id(x); i <= N; i += lowbit(i))
for (int j = y; j <= n; j += lowbit(j))
tr[i][j] += val;
}
int main() {
scanf("%d%d", &n, &m);
blo = sqrt(n);
N = id(n);
for (int i = 1; i <= n; i++) {
scanf("%d", a+i);
pa[ a[i] ] = i;
}
for (int i = 1; i <= n; i++) {
scanf("%d", b+i);
pb[ b[i] ] = i;
}
for (int i = 1; i <= n; i++)
add(pa[i], pb[i], 1);
for (int i = 0, op; i < m; i++) {
scanf("%d", &op);
if (op == 1) {
int l1, r1, l2, r2;
scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
printf("%d\n", query(l1, r1, l2, r2));
}
else {
int x, y;
scanf("%d%d", &x, &y);
int v1 = b[x], v2 = b[y];
add(pa[v1], x, -1);
add(pa[v2], y, -1);
add(pa[v1], y, 1);
add(pa[v2], x, 1);
pb[v1] = y;
pb[v2] = x;
swap(b[x], b[y]);
}
}
return 0;
}
浙公网安备 33010602011771号