bzoj2120
带修改莫队
抄了个板子,跟莫队很像
莫队是两维排序,带修改的莫队是三维排序,(block[l],block[r],time) 我们把询问按照这个顺序排序,然后像普通莫队一样转移,唯一不同的是块要开到sqrt(n),还有转移区间之前要把对应区间的修改修改好,用一个cur指针指向当前修改,如果这个修改在当前莫队l,r之间,那么修改统计数组和答案,然后把位置对应的颜色改变,否则指把对应位置颜色改变。注意修改我们要维护一个之前的颜色,就是修改之前的颜色,因为莫队经过排序后,时间是无序的,所以我们要撤销之前的修改,那么我们必须维护一个last,之前的颜色,如果修改就改成修改后的v颜色,否则撤销修改,改成last颜色
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N = 10010; int n, m, tot1, tot2, ans, size, l = 1, r, cur; #define Id(x) (x - 1) / size + 1 struct data { int pos, col, last; data(int pos = 0, int col = 0, int last = 0) : pos(pos), col(col), last(last) {} } c[N]; struct query { int l, r, id, tim; bool friend operator < (query A, query B) { if(Id(A.l) == Id(B.l)) { if(Id(A.r) == Id(B.r)) return A.id < B.id; return Id(A.r) < Id(B.r); } return Id(A.l) < Id(B.l); } } q[N]; int answer[N], a[N], cnt[1000010], t[1000010]; void add(int pos) { ++cnt[pos]; if(cnt[pos] == 1) ++ans; } void del(int pos) { --cnt[pos]; if(cnt[pos] == 0) --ans; } void change(int pos, int v) { if(pos >= l && pos <= r) { add(v); del(a[pos]); } a[pos] = v; } void solve() { sort(q + 1, q + tot2 + 1); for(int i = 1; i <= tot2; ++i) { while(cur < q[i].tim) { ++cur; change(c[cur].pos, c[cur].col); } while(cur > q[i].tim) { change(c[cur].pos, c[cur].last); --cur; } while(l < q[i].l) { del(a[l]); ++l; } while(l > q[i].l) { --l; add(a[l]); } while(r < q[i].r) { ++r; add(a[r]); } while(r > q[i].r) { del(a[r]); --r; } answer[q[i].id] = ans; } for(int i = 1; i <= tot2; ++i) printf("%d\n", answer[i]); } int main() { scanf("%d%d", &n, &m); size = sqrt(n); for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); t[i] = a[i]; } for(int i = 1; i <= m; ++i) { char opt[10]; int x, y; scanf("%s", opt); if(opt[0] == 'R') { scanf("%d%d", &x, &y); c[++tot1] = data(x, y, t[x]); t[x] = y; } if(opt[0] == 'Q') { ++tot2; scanf("%d%d", &q[tot2].l, &q[tot2].r); q[tot2].id = tot2; q[tot2].tim = tot1; } } solve(); return 0; }