P2464 题解
前言
题解全是分块,但顺着莫队标签刷题的我刷到了这题,就觉得这题是带修莫队。
唯一的带修莫队题解也没有离散化(所以时间复杂度带了个 map
的 \(O(\log n)\))。我来发个离散化的。
时间复杂度好像很极限,不过能过。
思路
先来一遍带修莫队板子。只有 add()
与 del()
不同,如下:
void add(int x) {cnt[x]++;}
void del(int x) {cnt[x]--;}
每次的答案就是 \(cnt_k\)。
把 cnt[]
换成 map <int , int>
即可获得 60 分(我的代码自带超大常数)。
此时就要离散化了。可能存在的数据有原本的 \(a_i\) 与每一次更新后的数 \(p\)。
将这两组数排序去重。然后将 \(a_i\),更新用的 \(p\),询问的 \(k\),都离散化。
这样,cnt[]
就可以使用数组了,省下了 map
的时间。注意要开双倍空间。
sort(t + 1, t + curt + 1); //t[] 存储了所有 ai 与更新用的 p。具体可以看完整代码。
int tt = unique(t + 1, t + curt + 1) - t - 1; //去重
for (int i = 1; i <= n; i++) a[i] = lower_bound(t + 1, t + tt + 1, a[i]) - t; //对三个数组都离散化
for (int i = 1; i <= curAsk; i++) ask[i].k = lower_bound(t + 1, t + tt + 1, ask[i].k) - t;
for (int i = 1; i <= curUpd; i++) upd[i].k = lower_bound(t + 1, t + tt + 1, upd[i].k) - t;
时间复杂度 \(O(n^{\frac{5}{3}} + n \log n)\)。前面的是带修莫队正常的时间,后面是离散化的时间。
完整代码
貌似不需要什么注释?长得和板子好像,基本只有上面提到的地方改动了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define space putchar(' ')
#define endl putchar('\n')
using namespace std;
typedef long long LL;
typedef long double LD;
void fastio()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
}
int read()
{
char op = getchar(); int x = 0, f = 1;
while (op < 48 || op > 57) {if (op == '-') f = -1; op = getchar();}
while (48 <= op && op <= 57) x = (x << 1) + (x << 3) + (op ^ 48), op = getchar();
return x * f;
}
void write(int x)
{
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
const int N = 1e5 + 5;
int len, a[N];
struct Ask {int l, r, k; int t, id;} ask[N]; int curAsk;
struct Upd {int id, k;} upd[N]; int curUpd;
bool cmp(Ask x, Ask y)
{
if (x.l / len != y.l / len) return x.l / len < y.l / len;
if (x.r / len != y.r / len) return x.r / len < y.r / len;
return x.t < y.t;
}
int cnt[N << 1];
inline void add(int x) {cnt[x]++;}
inline void del(int x) {cnt[x]--;}
inline void update(int l, int r, int t)
{
if (l <= upd[t].id && upd[t].id <= r) del(a[upd[t].id]), add(upd[t].k);
swap(a[upd[t].id], upd[t].k);
}
int ans[N];
int t[N << 1], curt;
int main()
{
int n = read(), m = read();
for (int i = 1; i <= n; i++) a[i] = read(), t[++curt] = a[i];
len = pow(n, 2.0 / 3);
for (int i = 1; i <= m; i++)
{
char op; cin >> op;
if (op == 'C')
{
int x = read(), y = read();
upd[++curUpd] = (Upd){x, y};
t[++curt] = y;
}
else
{
int l = read(), r = read(), k = read();
curAsk++, ask[curAsk] = (Ask){l, r, k, curUpd, curAsk};
}
}
sort(t + 1, t + curt + 1);
int tt = unique(t + 1, t + curt + 1) - t - 1;
for (int i = 1; i <= n; i++) a[i] = lower_bound(t + 1, t + tt + 1, a[i]) - t;
for (int i = 1; i <= curAsk; i++) ask[i].k = lower_bound(t + 1, t + tt + 1, ask[i].k) - t;
for (int i = 1; i <= curUpd; i++) upd[i].k = lower_bound(t + 1, t + tt + 1, upd[i].k) - t;
sort(ask + 1, ask + curAsk + 1, cmp);
for (int i = 1, l = 1, r = 0, t = 0; i <= curAsk; i++)
{
while (l < ask[i].l) del(a[l++]);
while (l > ask[i].l) add(a[--l]);
while (r < ask[i].r) add(a[++r]);
while (r > ask[i].r) del(a[r--]);
while (t < ask[i].t) update(ask[i].l, ask[i].r, ++t);
while (t > ask[i].t) update(ask[i].l, ask[i].r, t--);
ans[ask[i].id] = cnt[ask[i].k];
}
for (int i = 1; i <= curAsk; i++) write(ans[i]), endl;
return 0;
}
希望能帮助到大家!