【洛谷】1903:[国家集训队]数颜色 / 维护队列【带修莫队】
题目描述
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:
1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。
2、 R P Col 把第P支画笔替换为颜色Col。
为了满足墨墨的要求,你知道你需要干什么了吗?
输入输出格式
输入格式:
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。
第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。
第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
输出格式:
对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。
输入输出样例
说明
对于100%的数据,N≤50000,M≤50000,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
本题可能轻微卡常数
来源:bzoj2120
本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。
Solution
带修莫队模板题。
如何完成有时间线的修改操作??在询问中加一个到它时修改操作到了哪一步的时间线,再像以前一样分块排序。
计算答案时唯一不同的就是当把区间调成当前区间后,要看当前修改到哪一步,如果在它之前,那么就进行修改操作,更新答案。如果在它之后,那么进行撤销修改操作,更新答案。
修改操作中有一步很巧妙,这次修改相当于是把$a[pos]$和当前修改的$col$交换,下次如果有撤销操作,那么就是从$col$修改到$a[pos]$了。
洛谷数据加强后块要弄成$n^{\frac{2}{3}}$才能过叻QAQ太玄学叻....
Code
#include<bits/stdc++.h> using namespace std; int n, a[500005], m; int blo[500005]; void read(int &x) { x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); } struct Node { int l, r, id, ans, pos; } Q[500005]; bool cmp(Node a, Node b) { if(blo[a.l] != blo[b.l]) return a.l < b.l; if(blo[a.r] != blo[b.r]) return a.r < b.r; return a.id < b.id; } bool cmp2(Node a, Node b) { return a.pos < b.pos; } struct Edge { int pos, to; } C[500005]; int L, R, cnttot, cnt[1000005]; inline void update(int x) { if(C[x].pos >= L && C[x].pos <= R) { if(!--cnt[a[C[x].pos]]) -- cnttot; if(!cnt[C[x].to] ++) ++ cnttot; } swap(a[C[x].pos], C[x].to); } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) read(a[i]); int bl = pow(n, 0.666666666); for(int i = 1; i <= n; i ++) blo[i] = i / bl + 1; int tot = 0, totc = 0; scanf("\n"); for(int i = 1; i <= m; i ++) { char opt; while(scanf("%c", &opt) == 1) if(opt == 'Q' || opt == 'R') break; if(opt == 'Q') { int l, r; read(l); read(r); Q[++tot].l = l, Q[tot].r = r; Q[tot].id = totc, Q[tot].pos = i; } else { int x, col; read(x); read(col); ++ totc; C[totc].to = col, C[totc].pos = x; } } sort(Q + 1, Q + 1 + tot, cmp); int now = 0; for(int i = 1; i <= tot; i ++) { while(Q[i].l < L) { L --; if(!cnt[a[L]]++) cnttot ++; } while(Q[i].l > L) { if(!--cnt[a[L]]) cnttot --; L ++; } while(Q[i].r < R) { if(!--cnt[a[R]]) cnttot --; R --; } while(Q[i].r > R) { R ++; if(!cnt[a[R]]++) cnttot ++; } while(now < Q[i].id) update(++now); while(now > Q[i].id) update(now--); Q[i].ans = cnttot; } sort(Q + 1, Q + 1 + tot, cmp2); for(int i = 1; i <= tot; i ++) printf("%d\n", Q[i].ans); return 0; }