洛谷 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;
}
posted @ 2023-07-05 15:37  zltzlt  阅读(58)  评论(0编辑  收藏  举报