洛谷 P1903 [国家集训队]数颜色 / 维护队列 题解
\(Description\)
\(Solution\)
带修莫队板子题。
就是再多开一维时间轴,把每次修改修改前的颜色和修改后的颜色都记录下来。
离线处理。
枚举操作时,类似于普通的莫队,while(操作时间)
看看是该插入还是删除,然后直接修改就完了。
贴下代码吧,直接看代码比较好理解。
\(Code\)
#include <bits/stdc++.h>
#define get_B(x) x / B
using namespace std;
namespace IO{
inline int read(){
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
template <typename T> inline void write(T x){
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
int n, m, B, res;
int c[N], col[N];
char op[3];
struct Upd{
int pos, col, pre;
}p[N];
struct Qry{
int l, r, t, pos;
friend bool operator < (Qry a, Qry b){
if(get_B(a.l) != get_B(b.l)) return get_B(a.l) < get_B(b.l);
return get_B(a.r) != get_B(b.r) ? get_B(a.r) < get_B(b.r) : a.t < b.t;
}
}q[N];
int tp, tq;
int vis[M], ans[N];
int main(){
n = read(), m = read();
for(int i = 1; i <= n; ++i) col[i] = c[i] = read();
for(int i = 1; i <= m; ++i){
scanf("%s", op);
int x = read(), y = read();
if(op[0] == 'R') p[++tp] = (Upd){x, y, c[x]}, c[x] = y;
else q[++tq] = (Qry){x, y, tp, tq};
}
if(!tq) return 0;
B = pow(n, 0.7);
sort(q + 1, q + 1 + tq);
int l = 1, r = 0, t = 0;
for(int i = 1; i <= tq; ++i){
while(l > q[i].l) res += !vis[col[--l]]++;
while(l < q[i].l) res -= !--vis[col[l++]];
while(r < q[i].r) res += !vis[col[++r]]++;
while(r > q[i].r) res -= !--vis[col[r--]];
while(t > q[i].t){
int x = p[t].pos;
if(l <= x && x <= r) res -= !--vis[col[x]];
col[x] = p[t--].pre;
if(l <= x && x <= r) res += !vis[col[x]]++;
}
while(t < q[i].t){
int x = p[++t].pos;
if(l <= x && x <= r) res -= !--vis[col[x]];
col[x] = p[t].col;
if(l <= x && x <= r) res += !vis[col[x]]++;
}
ans[q[i].pos] = res;
}
for(int i = 1; i <= tq; ++i) write(ans[i]), puts("");
return 0;
}
\[\_EOF\_
\]