Problem :
給一個序列,每次詢問一個區間裏面的數字種類數量,或者修改某一個位置的值。
Solution :
第一關鍵字分塊排序左端點,第二關鍵字分塊排序右端點,第三關鍵字排序詢問順序。c++
左端點移動總的時間複雜度爲 q * block_size + block_num * block_size
右端點移動總的時間複雜度爲 q * block_size + block_num * block_num * block_size
詢問端點總的時間複雜度爲 block_num * block_num * n
故取block_size = n^(2/3)spa
#include <bits/stdc++.h> using namespace std; const int N = 50008; int a[N], b[N], cnt[N * 20], vis[N], ans[N]; int sum, n, m, bklen; int tot1, tot2; struct query1 { int l, r, x, lb, rb, id; query1(){} query1(int l, int r, int x, int id) : l(l), r(r), x(x), id(id) { lb = (l - 1) / bklen + 1; rb = (r - 1) / bklen + 1; } bool operator < (const query1 &b) const { if (lb != b.lb) return lb < b.lb; if (rb != b.rb) return rb < b.rb; return x < b.x; } }q1[N]; struct query2 { int pos, x, y; query2(){} query2(int pos, int x, int y) : pos(pos), x(x), y(y){} }q2[N]; void update(int pos) { if (vis[pos]) { if (cnt[a[pos]] == 1) sum--; cnt[a[pos]]--; } else { if (cnt[a[pos]] == 0) sum++; cnt[a[pos]]++; } vis[pos] ^= 1; } void change(int pos, int x) { if (vis[pos]) { update(pos); a[pos] = x; update(pos); } else a[pos] = x; } int main() { cin.sync_with_stdio(0); cin >> n >> m; bklen = pow(n, 2.0 / 3); for (int i = 1; i <= n; ++i) cin >> a[i], b[i] = a[i]; for (int i = 1; i <= m; ++i) { string s; int l, r; cin >> s >> l >> r; l++; if (s[0] == 'Q') { ++tot1; //若是寫到下面的話,可能會致使後面的tot1沒有+1 q1[tot1] = query1(l, r, tot2, tot1); } else { q2[++tot2] = query2(l, b[l], r); b[l] = r; } } sort(q1 + 1, q1 + tot1 + 1); sum = 0; for (int i = 1, l = 1, r = 0, x = 0; i <= tot1; ++i) { while (x < q1[i].x) {++x; change(q2[x].pos, q2[x].y);} while (x > q1[i].x) {change(q2[x].pos, q2[x].x); --x;} while (r < q1[i].r) update(++r); while (r > q1[i].r) update(r--); while (l < q1[i].l) update(l++); while (l > q1[i].l) update(--l); ans[q1[i].id] = sum; } for (int i = 1; i <= tot1; ++i) cout << ans[i] << endl; }