Luogu P1903 [国家集训队]数颜色 / 维护队列___带修莫队

题目大意:

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:
1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。
2、 R P Col 把第P支画笔替换为颜色Col。
在这里插入图片描述

分析:

没有修改操作就是直接上莫队即可
有了修改操作我们就引入一个时间戳,对于一个询问,就记录一下它前面有多少个修改
在莫队过程中进行修改即可

代码:

#include 

#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)

#define N 150005

using namespace std;

typedef long long ll;

struct Node {
    int l, r, id, cp;
}q1[N];
struct Code {
	int id, x;
}q2[N];
int beln[N], ans[N], cnt[N*7], a[N], n, m, now, tot1, tot2;

void read(int &x) {
	int f = 1; x = 0; char s = getchar();
	while (s < '0' || s > '9') { if (s == '-') f = - 1; s = getchar(); }
	while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
	x = x * f;
}

bool cmp(Node aa, Node bb) {
    return (beln[aa.l] == beln[bb.l]) ? ((beln[aa.r] == beln[bb.r] ? aa.cp < bb.cp : beln[aa.r] < beln[bb.r])) : beln[aa.l] < beln[bb.l];
}

void add(int x) {
    if (cnt[x] == 0) ++now; ++cnt[x];
}

void del(int x) {
    if (cnt[x] == 1) --now; --cnt[x];
}

void write(int x) {
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

int main() {
    read(n); read(m);
    int siz = pow(n, 2.0 / 3.0);
    rep(i, 1, ceil((double)n / siz)) 
	    rep(j, (i - 1) * siz + 1, i * siz) beln[j] = i;
		         
    rep(i, 1, n) read(a[i]);
    char opt[5];
	rep(i, 1, m) {
	    scanf("%s", opt);
		if (opt[0] == 'Q') ++tot1, read(q1[tot1].l), read(q1[tot1].r), q1[tot1].id = tot1, q1[tot1].cp = tot2; 
		   else ++tot2, read(q2[tot2].id), read(q2[tot2].x);
	}
    sort(q1 + 1, q1 + tot1 + 1, cmp);
    int l = 1, r = 0, z = 0;
    rep(i, 1, tot1) {
        while (l < q1[i].l) del(a[l]), l++;
        while (l > q1[i].l) l--, add(a[l]);
        while (r < q1[i].r) r++, add(a[r]);
        while (r > q1[i].r) del(a[r]), r--;
        while (z < q1[i].cp) {
        	++z; 
			if (q1[i].l <= q2[z].id && q2[z].id <= q1[i].r) del(a[q2[z].id]), add(q2[z].x);
        	swap(a[q2[z].id], q2[z].x);
		}
		while (z > q1[i].cp) {
        	if (q1[i].l <= q2[z].id && q2[z].id <= q1[i].r) del(a[q2[z].id]), add(q2[z].x);
        	swap(a[q2[z].id], q2[z].x);	
			--z;	
		}
		ans[q1[i].id] = now;
    }
	rep(i, 1, tot1) write(ans[i]), printf("\n");
    return 0;
}

你可能感兴趣的:(C++,莫队)