洛谷 P7722 [Ynoi2007] tmpq
被踩爆了好神的题啊!
转化一下题意,给出三个数组 \(a, b, c\),每次可以单点修改 \(a, b, c\),询问即求 \(b_i = a_j = c_k, 1 \le i < j < k \le r\) 的数量。
发现每种颜色是独立的,故先把询问离线下来,把颜色分开单独考虑。设 \(b_i = a_j = c_k = w\)。考虑根号分治。设 \(B = \sqrt{n + m}\)。
- 如果 \(w\) 的出现次数 \(\le B\),直接暴力计算 dp 值,在 \(k\) 处加即可,查询直接查询前缀和,可以用分块平衡复杂度,\(O(1)\) 单点修改,\(O(B)\) 查询即可。
- 如果 \(w\) 的出现次数 \(> B\),这样的数不超过 \(B\) 个,对于每个数维护一个动态 dp,仍然是使用分块维护前缀矩阵积,\(O(B)\) 单点修改,\(O(1)\) 查询即可。
你会发现每一处都奇妙地平衡了时间复杂度。因此时间复杂度 \(O((n + m) \sqrt{n + m})\)。
code
// Problem: P7722 [Ynoi2007] tmpq
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7722
// Memory Limit: 64 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;
/*
转化一下题意,给出三个数组 $a, b, c$,每次可以单点修改 $a, b, c$,询问即求 $b_i = a_j = c_k, 1 \le i < j < k \le r$ 的数量。
发现每种颜色是独立的,故先把询问离线下来,把颜色分开单独考虑。设 $b_i = a_j = c_k = w$。考虑根号分治。设 $B = \sqrt{n + m}$。
- 如果 $w$ 的出现次数 $\le B$,直接暴力计算 dp 值,在 $k$ 处加即可,查询直接查询前缀和,可以用分块平衡复杂度,$O(1)$ 单点修改,$O(B)$ 查询即可。
- 如果 $w$ 的出现次数 $> B$,这样的数不超过 $B$ 个,对于每个数维护一个动态 dp,仍然是使用分块维护前缀矩阵积,$O(B)$ 单点修改,$O(1)$ 查询即可。
你会发现每一处都奇妙地平衡了时间复杂度。因此时间复杂度 $O((n + m) \sqrt{n + m})$。
*/
const int maxn = 200100;
int n, m, B, a[maxn], b[maxn], c[maxn], bel[maxn], L[maxn], R[maxn], blo, oa[maxn];
ll ans[maxn];
vector<int> app[maxn];
vector<ll> lf[maxn];
struct wwh {
int op, x, y;
} qq[maxn];
// =================== small ===================
namespace BLS {
ll a[maxn], b[maxn];
inline void update(int x, ll y) {
a[x] += y;
b[bel[x]] += y;
}
inline ll query(int x) {
ll res = 0;
for (int i = 1; i < bel[x]; ++i) {
res += b[i];
}
for (int i = L[bel[x]]; i <= x; ++i) {
res += a[i];
}
return res;
}
}
inline void update(int t) {
if ((int)app[t].size() > B) {
return;
}
ll A = 0, B = 0, C = 0, lst = 0;
for (int i = 0; i < (int)app[t].size(); ++i) {
int k = app[t][i];
if (c[a[k]] == t) {
C += B;
}
if (a[k] == t) {
B += A;
}
if (b[a[k]] == t) {
++A;
}
BLS::update(k, C - lst - lf[t][i]);
lf[t][i] = C - lst;
lst = C;
}
}
inline void solve_small() {
for (int i = 1; i <= n; ++i) {
update(i);
}
for (int i = 1; i <= m; ++i) {
int op = qq[i].op, x = qq[i].x, y = qq[i].y;
if (op == 1) {
int t = a[x];
a[x] = y;
update(t);
update(b[t]);
update(c[t]);
update(y);
update(b[y]);
update(c[y]);
} else {
ans[i] += BLS::query(x);
}
}
}
// ==================== big ====================
struct node {
ll a, b, c, ab, bc, abc;
node(ll x = 0, ll y = 0, ll z = 0, ll u = 0, ll v = 0, ll w = 0) : a(x), b(y), c(z), ab(u), bc(v), abc(w) {}
} f[maxn];
inline node operator + (const node &a, const node &b) {
node res;
res.a = a.a + b.a;
res.b = a.b + b.b;
res.c = a.c + b.c;
res.ab = a.ab + b.ab + a.a * b.b;
res.bc = a.bc + b.bc + a.b * b.c;
res.abc = a.abc + b.abc + a.ab * b.c + a.a * b.bc;
return res;
}
namespace BLM {
node a[maxn], b[maxn];
inline void init() {
for (int i = 1; i <= bel[n]; ++i) {
a[L[i]] = f[L[i]];
for (int j = L[i] + 1; j <= R[i]; ++j) {
a[j] = a[j - 1] + f[j];
}
b[i] = b[i - 1] + a[R[i]];
}
}
inline void update(int x) {
a[L[x]] = f[L[x]];
for (int i = L[x] + 1; i <= R[x]; ++i) {
a[i] = a[i - 1] + f[i];
}
for (int i = 1; i <= bel[n]; ++i) {
b[i] = b[i - 1] + a[R[i]];
}
}
inline node query(int x) {
return b[bel[x] - 1] + a[x];
}
}
inline void solve_big() {
for (int k = 1; k <= n; ++k) {
if ((int)app[k].size() <= B) {
continue;
}
for (int i = 1; i <= n; ++i) {
f[i] = node();
a[i] = oa[i];
}
for (int x : app[k]) {
f[x] = node(b[a[x]] == k, a[x] == k, c[a[x]] == k);
}
BLM::init();
for (int i = 1; i <= m; ++i) {
int op = qq[i].op, x = qq[i].x, y = qq[i].y;
if (op == 1) {
if (b[a[x]] == k || a[x] == k || c[a[x]] == k || b[y] == k || y == k || c[y] == k) {
f[x] = node(b[y] == k, y == k, c[y] == k);
BLM::update(bel[x]);
}
a[x] = y;
} else {
ans[i] += BLM::query(x).abc;
}
}
}
}
void solve() {
scanf("%d%d", &n, &m);
B = sqrt(n + m);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
oa[i] = a[i];
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &b[i]);
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &c[i]);
}
for (int i = 1; i <= n; ++i) {
app[a[i]].pb(i);
app[b[a[i]]].pb(i);
app[c[a[i]]].pb(i);
}
blo = sqrt(n);
for (int i = 1; i <= n; ++i) {
bel[i] = (i - 1) / blo + 1;
if (!L[bel[i]]) {
L[bel[i]] = i;
}
R[bel[i]] = i;
}
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &qq[i].op, &qq[i].x);
if (qq[i].op == 1) {
scanf("%d", &qq[i].y);
app[qq[i].y].pb(qq[i].x);
app[b[qq[i].y]].pb(qq[i].x);
app[c[qq[i].y]].pb(qq[i].x);
}
}
for (int i = 1; i <= n; ++i) {
sort(app[i].begin(), app[i].end());
app[i].resize(unique(app[i].begin(), app[i].end()) - app[i].begin());
lf[i].resize(app[i].size());
}
solve_small();
solve_big();
for (int i = 1; i <= m; ++i) {
if (qq[i].op == 2) {
printf("%lld\n", ans[i]);
}
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}