时间复杂度为:\(O(n^{5 / 3})\)。这里假设了数组大小,查询次数、修改次数均为n。
无注释板子代码
int n, m, k;
int a[N];
int qcnt, rcnt, B, res;
int num[N], ans[N];
struct query{
int l, r, t, id;
bool operator < (const query& x) const{
if(l / B != x.l / B) return l < x.l;
if(r / B != x.r / B) return r < x.r;
return t < x.t;
}
}Q[N];
struct operation{
int p, x;
}R[N];
void add(int x){
}
void del(int x){
}
void changeT(int l, int r, int t){
if(R[t].p >= l && R[t].p <= r){
}
swap(R[t].x, a[R[t].p]);
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= m; i ++){
char op;
int l, r, p, x;
cin >> op;
if(op == 'Q'){
cin >> l >> r;
++qcnt; Q[qcnt] = {l, r, rcnt, qcnt};
}else{
cin >> p >> x;
++rcnt; R[rcnt] = {p, x};
}
}
B = pow(n, 2.0 / 3.0);
if(B == 0) B = 1;
sort(Q + 1, Q + 1 + qcnt);
int t = 0;
for(int i = 1, l = 1, r = 0; i <= qcnt; i ++){
while(l > Q[i].l) add(a[--l]);
while(r < Q[i].r) add(a[++r]);
while(l < Q[i].l) del(a[l++]);
while(r > Q[i].r) del(a[r--]);
while(t < Q[i].t) changeT(l, r, ++t);
while(t > Q[i].t) changeT(l, r, t--);
ans[Q[i].id] = res;
}
for(int i = 1; i <= qcnt; i ++) cout << ans[i] << endl;
}
带注释板子代码
int n, m, k;
/*
a[]记录原数组。
qcnt记录查询次数, rcnt记录修改次数。
B为块长。
res记录当前区间的答案。
num[]为辅助数组,帮助O(1)转移区间答案。
ans[]记录查询答案。
*/
int a[N];
int qcnt, rcnt, B, res;
int num[N], ans[N];
/*
记录查询,以左端点所在块的块号为第一关键字,升序排序;
以右端点所在块的块号为第二关键字,升序排序;
以该查询的时间(即查询该区间时的修改次数)为第三关键字,升序排序。
*/
struct query{
int l, r, t, id;
bool operator < (const query& x) const{
if(l / B != x.l / B) return l < x.l;
if(r / B != x.r / B) return r < x.r;
return t < x.t;
}
}Q[N];
/*
记录修改。
p为修改的位置。
x为修改后的值。
*/
struct operation{
int p, x;
}R[N];
void add(int x){
/* 区间外扩1格对答案的改变 */
}
void del(int x){
/* 区间收缩1格对答案的改变 */
}
/*
如果回退或前进的修改的位置在区间内,就会对答案造成影响,要改变答案并且修改数组;
如果不在,那就直接修改数组就行。
*/
void changeT(int l, int r, int t){
if(R[t].p >= l && R[t].p <= r){
add(R[t].x);
del(a[R[t].p]);
}
/* 这里很妙,将修改前的值放进R里面,这样下次回退就还是执行一样的操作,节约代码和思维难度。 */
swap(R[t].x, a[R[t].p]);
}
void solve(){
/* 输入 */
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i];
/* 记录查询和修改,离线处理。 */
for(int i = 1; i <= m; i ++){
char op;
int l, r, p, x;
cin >> op;
if(op == 'Q'){
cin >> l >> r;
++qcnt; Q[qcnt] = {l, r, rcnt, qcnt};
}else{
cin >> p >> x;
++rcnt; R[rcnt] = {p, x};
}
}
/* 块长最优为 n^(2/3), 能保证时间复杂度都是较优的 */
B = pow(n, 2.0 / 3.0);
/* 边界判断,防止B为0的特殊情况,这个非常重要。 */
if(B == 0) B = 1;
/* 排序 */
sort(Q + 1, Q + 1 + qcnt);
/* 记录当前的时间。 */
int t = 0;
/*处理询问。 */
for(int i = 1, l = 1, r = 0; i <= qcnt; i ++){
/* 顺序很重要,要先扩张区间,然后再收缩区间,防止l > r。 */
while(l > Q[i].l) add(a[--l]);
while(r < Q[i].r) add(a[++r]);
while(l < Q[i].l) del(a[l++]);
while(r > Q[i].r) del(a[r--]);
while(t < Q[i].t) changeT(l, r, ++t);
while(t > Q[i].t) changeT(l, r, t--);
ans[Q[i].id] = res;
}
/* 输出 */
for(int i = 1; i <= qcnt; i ++) cout << ans[i] << endl;
}
示例代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define endl '\n'
#define fi first
#define se second
#define pb push_back
#define PII pair<int, int>
#define lowbit(x) ((x) & (-(x)))
#define all(a) a.begin(), a.end()
#define debug(x) cout << #x << " = " << (x) << "\n";
#define vdebug(a) cout << #a << " = "; for(auto& x: a) cout << x << " "; cout << "\n";
#define vlrdebug(a, l, r) cout << #a << " = "; for(auto i = l; i <= r; i ++) cout << a[i] << " "; cout << "\n";
#define lc ((p) << 1)
#define rc ((p) << 1 | 1)
const int N = 1e6 + 10, M = 1010;
const int mod = 1e9 + 7, MOD = 998244353;
const int INF = 0x3f3f3f3f;
const long long inf = 0x3f3f3f3f3f3f3f3f;
const int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
int n, m, k;
int a[N];
int qcnt, rcnt, B, res;
int num[N], ans[N];
struct query{
int l, r, t, id;
bool operator < (const query& x) const{
if(l / B != x.l / B) return l < x.l;
if(r / B != x.r / B) return r < x.r;
return t < x.t;
}
}Q[N];
struct operation{
int p, x;
}R[N];
void add(int x){
if(num[x] == 0) res ++;
num[x] ++;
}
void del(int x){
num[x] --;
if(num[x] == 0) res --;
}
void changeT(int l, int r, int t){
if(R[t].p >= l && R[t].p <= r){
add(R[t].x);
del(a[R[t].p]);
}
swap(R[t].x, a[R[t].p]);
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= m; i ++){
char op;
int l, r, p, x;
cin >> op;
if(op == 'Q'){
cin >> l >> r;
++qcnt; Q[qcnt] = {l, r, rcnt, qcnt};
}else{
cin >> p >> x;
++rcnt; R[rcnt] = {p, x};
}
}
B = pow(n, 2.0 / 3.0);
if(B == 0) B = 1;
sort(Q + 1, Q + 1 + qcnt);
int t = 0;
for(int i = 1, l = 1, r = 0; i <= qcnt; i ++){
while(l > Q[i].l) add(a[--l]);
while(r < Q[i].r) add(a[++r]);
while(l < Q[i].l) del(a[l++]);
while(r > Q[i].r) del(a[r--]);
while(t < Q[i].t) changeT(l, r, ++t);
while(t > Q[i].t) changeT(l, r, t--);
ans[Q[i].id] = res;
}
for(int i = 1; i <= qcnt; i ++) cout << ans[i] << endl;
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while(_ --) solve();
return 0;
}