\(\text{Solution}\)
很容易想到映射处理
以 \(a\) 为基准,主要是因为 \(a\) 不修改
然后就是要解决这么一个问题,带单点修改的二维数点
考虑 \(CDQ\) 分治
当前只考虑分治中心左边区间的修改操作对右边查询的贡献
树状数组即可维护
(第一道 \(CDQ\) 将动态问题转化为静态问题)
\(\text{Code}\)
#include <cstdio>
#include <algorithm>
#define IN inline
#define RE register
using namespace std;
const int N = 2e5 + 5;
int n, m, cnt, qt, a[N], b[N], pos[N], ans[N];
struct node{int ty, x, l, r, v, id;}Q[N * 11], q[N * 11];
IN bool cmp(node a, node b){return a.x < b.x ? 1 : (a.x == b.x ? a.ty > b.ty : 0);}
struct BIT{
int c[N];
IN int lowbit(int x){return x & (-x);}
IN void Add(int x, int v){for(; x <= n; x += lowbit(x)) c[x] += v;}
IN int getsum(int x){int s = 0; for(; x; x -= lowbit(x)) s += c[x]; return s;}
IN int Query(int l, int r){return getsum(r) - getsum(l - 1);}
}T;
void CDQ(int l, int r)
{
if (l == r) return;
int mid = l + r >> 1; CDQ(l, mid), CDQ(mid + 1, r);
for(RE int k = l; k <= r; k++) q[k] = Q[k];
sort(Q + l, Q + mid + 1, cmp), sort(Q + mid + 1, Q + r + 1, cmp);
int j, i;
for(j = mid + 1, i = l; j <= r; j++)
if (Q[j].ty == 1)
{
for(; i <= mid && Q[i].x <= Q[j].x; ++i) if (Q[i].ty == 2) T.Add(Q[i].l, Q[i].r);
ans[Q[j].id] += T.Query(Q[j].l, Q[j].r) * Q[j].v;
}
for(RE int k = l; k < i; k++) if (Q[k].ty == 2) T.Add(Q[k].l, -Q[k].r);
for(RE int k = l; k <= r; k++) Q[k] = q[k];
}
int main()
{
scanf("%d%d", &n, &m);
for(RE int i = 1; i <= n; i++) scanf("%d", &a[i]), pos[a[i]] = i;
for(RE int i = 1; i <= n; i++) scanf("%d", &b[i]), b[i] = pos[b[i]], Q[++cnt] = node{2, i, b[i], 1};
for(RE int i = 1, ty, l, r, x, y; i <= m; i++)
{
scanf("%d%d%d", &ty, &l, &r);
if (ty == 1)
scanf("%d%d", &x, &y), Q[++cnt] = node{1, y, l, r, 1, ++qt}, Q[++cnt] = node{1, x - 1, l, r, -1, qt};
else{
Q[++cnt] = node{2, l, b[l], -1}, Q[++cnt] = node{2, r, b[r], -1};
swap(b[l], b[r]), Q[++cnt] = node{2, l, b[l], 1}, Q[++cnt] = node{2, r, b[r], 1};
}
}
CDQ(1, cnt);
for(RE int i = 1; i <= qt; i++) printf("%d\n", ans[i]);
}