带修莫队板子

时间复杂度为:\(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;
} 
posted @ 2025-12-05 17:37  _hu  阅读(3)  评论(0)    收藏  举报