洛谷 P7722 [Ynoi2007] tmpq
被踩爆了好神的题啊!
转化一下题意,给出三个数组 ,每次可以单点修改 ,询问即求 的数量。
发现每种颜色是独立的,故先把询问离线下来,把颜色分开单独考虑。设 。考虑根号分治。设 。
- 如果 的出现次数 ,直接暴力计算 dp 值,在 处加即可,查询直接查询前缀和,可以用分块平衡复杂度, 单点修改, 查询即可。
- 如果 的出现次数 ,这样的数不超过 个,对于每个数维护一个动态 dp,仍然是使用分块维护前缀矩阵积, 单点修改, 查询即可。
你会发现每一处都奇妙地平衡了时间复杂度。因此时间复杂度 。
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App