题目链接
首先我们要知道,普通的莫队算法是不资瓷修改操作的,
不过后人对莫队算法加以改进
发明了资瓷修改的莫队算法
在进行修改操作的时候,修改操作是会对答案产生影响的(废话)
那么我们如何避免修改操作带来的影响呢?
首先我们需要把查询操作和修改操作分别记录下来。
在记录查询操作的时候,需要增加一个变量来记录离本次查询最近的修改的位置
然后套上莫队的板子,与普通莫队不一样的是,你需要用一个变量记录当前已经进行了几次修改
对于查询操作,如果当前改的比本次查询需要改的少,就改过去
反之如果改多了就改回来
说的听绕口的
比如,我们现在已经进行了3次修改,本次查询是在第5次修改之后,那我们就执行第4,5次修改
这样就可以避免修改操作对答案产生的影响了
#include
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = N;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
int n, m;
int where[maxn]; // 统计左右端点在哪个块?
int Cnum, Qnum;
// Cnum 修改操作的个数,Qnum 查询操作的个数
int color[maxn], a[maxn], ans, base, out[maxn];
// base是块的大小,out是用来输出答案的,ans是统计答案用的, color 统计颜色个数
struct Quary {
int l, r, pre, id;
}Q[maxn];
// 魔改版的莫队排序函数很快
int comp(const Quary &a,const Quary &b) {
return a.l / base == b.l / base ? a.r / base == b.r / base ? a.pre < b.pre : a.r < b.r : a.l < b.l;
}
struct Change {
int pos, val;
}C[maxn];
inline void Add(int val) {
if(++ color[val] == 1) ans ++;
}
inline void Delete(int val) {
if(-- color[val] == 0) ans --;
}
inline void work(int now, int i) {
if(C[now].pos >= Q[i].l && C[now].pos <= Q[i].r) { //注意这里要判断是否在查询范围内?
if(-- color[a[C[now].pos]] == 0) ans --;
if(++ color[C[now].val] == 1) ans ++;
}
swap(C[now].val,a[C[now].pos]);
// 你把pos改成了val。下次你再修改就是相当于还原,所以就是把val和a值直接交换就可以了
}
inline void Moqueue() {
int l = 1, r = 0, now = 0;
for(int i = 1; i <= Qnum; ++ i) {
while(l > Q[i].l) Add(a[--l]);
while(r < Q[i].r) Add(a[++r]);
while(l < Q[i].l) Delete(a[l++]);
while(r > Q[i].r) Delete(a[r--]);
while(now < Q[i].pre) work(++now,i);
while(now > Q[i].pre) work(now--,i);
out[Q[i].id] = ans;
}
for(int i = 1; i <= Qnum; ++ i)
printf("%d\n",out[i]);
}
int main() {
read(n,m);
base = pow(n,0.666); // n^(2/3)次方 块的大小
for(int i = 1; i <= n; ++ i) {
read(a[i]);
where[i] = (i - 1) / base + 1;
}
while(m --) {
char op[5];
scanf("%s",op);
if(*op == 'Q') {
++ Qnum;
read(Q[Qnum].l,Q[Qnum].r);
Q[Qnum].id = Qnum;
Q[Qnum].pre = Cnum;
} else {
++ Cnum;
read(C[Cnum].pos,C[Cnum].val);
}
}
sort(Q+1,Q+1+Qnum,comp);
Moqueue();
return 0;
}