写这篇博客的主要目的是记录 带修莫队 的实现方法.
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:
1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。
2、 R P Col 把第P支画笔替换为颜色Col。
为了满足墨墨的要求,你知道你需要干什么了吗?
普通莫队 的分块大小为 , 按照 块 为第一关键字, 右端点 为第二关键字排序.
带修莫队 的分块大小为 ,按照 块 为第一关键字,
若 右端点 不在同一个块中, 按 右端点为第二关键字 排序, 否则按 操作时间 为第二关键字 排序 .
其余就是莫队基础操作了, 这里不再赘述 .
没什么好说的 …
#include <bits/stdc++.h>
const int maxn = 1000005;
int read(){
int flag = 1;
char c;
while (!isdigit(c = getchar())) if(c == '-') flag = -1;
int sum = 0;
while(isdigit(c)) sum = sum*10 + c - '0', c = getchar();
return sum * flag;
}
int N, M, cnt, _cnt, Ans, Tong[maxn], A[maxn], _Ans[maxn];
int block_size;
struct Query{ int L, R, block, index, tim, ans; } Q[maxn];
struct Revise{ int pos, v; } R[maxn];
bool cmp(const Query &a, const Query &b){
if(a.block != b.block) return a.block < b.block;
else if(a.R / block_size != b.R / block_size) return a.R < b.R; // WRONG 带修改莫队的理解
return a.tim < b.tim;
}
bool _cmp(const Query &a, const Query &b){ return a.index < b.index; } // 没有加取址符号,速度慢
int LL, RR;
void Change(int tim){
int pos = R[tim].pos, v = R[tim].v;
if(LL <= pos && pos <= RR){
Ans -= !-- Tong[A[pos]];
Ans += !Tong[v] ++;
}
R[tim].v ^= A[pos] ^= R[tim].v ^= A[pos];
}
int main(){
N = read(), M = read();
block_size = std::pow(N, 2.0/3);
for(register int i = 1; i <= N; i ++) A[i] = read();
char s[2];
for(register int i = 1; i <= M; i ++){
scanf(" %s", s);
if(s[0] == 'Q'){
cnt ++;
Q[cnt].L = read(), Q[cnt].R = read();
Q[cnt].block = Q[cnt].L / block_size + 1;
Q[cnt].index = cnt;
Q[cnt].tim = _cnt;
}else if(s[0] == 'R')
_cnt++, R[_cnt].pos = read(), R[_cnt].v = read();
}
std::sort(Q+1, Q+cnt+1, cmp);
register int l = 1, r = 0, tim = 0;
for(register int i = 1; i <= M; i ++){
LL = Q[i].L;
RR = Q[i].R;
while(l < LL) Ans -= !-- Tong[A[l ++]];
while(l > LL) Ans += !Tong[A[-- l]] ++;
while(r < RR) Ans += !Tong[A[++ r]] ++;
while(r > RR) Ans -= !-- Tong[A[r --]];
while(tim < Q[i].tim) Change(++ tim);
while(tim > Q[i].tim) Change(tim --);
Q[i].ans = Ans;
_Ans[Q[i].index] = Ans;
}
//std::cerr << (double)clock() / CLOCKS_PER_SEC << std::endl;
for(register int i = 1; i <= cnt; i ++) printf("%d
", _Ans[i]);
return 0;
}