「学习笔记/刷题记录」带修莫队算法([国家集训队] 数颜色 / 维护队列)

前言#

玩了半个下午的卡常,快玩出花了,我都怀疑最后可能有人会把我举报卡评测,如下图
image
只能说,inline 是个好东西,直接快了近 2s

进入正题#

要知道,最普通的莫队算法是不支持修改的,前面也提到过,这个带修莫队(可持久化莫队)是后来人改进得来的(好像还改进到在线莫队了?我不清楚,错了别喷),在存储方面,带修莫队只是增加了新的一维——时间轴,代表这是第几次修改后的查询
来看看下面这道题(第一次交全RE了)

[国家集训队] 数颜色 / 维护队列#

墨墨购买了一套 N 支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:
1、Q L R 代表询问你从第 L 支画笔到第 R 支画笔中共有几种不同颜色的画笔。
2、R P Col 把第 P 支画笔替换为颜色 Col
为了满足墨墨的要求,你知道你需要干什么了吗?


和【小Z的袜子】相比,这道题不用维护概率那个恶心人的东西,只需要维护数量就好了,它的 add() 和 del() 函数和一般的莫队写法都差不多,只是注意,在本题中如果某种颜色的画笔数量减为 0 了,那么 ans 就要 1;某种画笔的数量从 0 变成了 1,那么 ans 就要 +1
而我们多了时间轴这意味,可以这么理解一下,如果当前正在查询的时间轴 T,比你现在的时间轴 t 要大,那你就把你的 t 改到 T,就是你改少了再多改写,同理,你改多了就再改回来
具体怎么改,看代码吧,其实只要搞懂莫队的思想,带修莫队也没什么能讲的
代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read() {
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 2e6 + 5;

int n, m, num, cnta, cntc, ans;
int c[N], pos[N], cnt[N], res[N];

struct xunwen {
	int l, r, t, id;
	int operator < (const xunwen &b) {
		return pos[l] == pos[b.l] ? pos[r] == pos[b.r] ? t < b.t : 
		pos[r] < pos[b.r] : pos[l] < pos[b.l];
	}
} ask[N];

struct xiugai {
	int l, r;
} change[N];

inline void add(int x) {
	ans += !cnt[x];
	++ cnt[x];
}

inline void del(int x) {
	ans -= !-- cnt[x];
}

inline void pushup(int x, int t) {
	if (ask[x].l <= change[t].l && change[t].l <= ask[x].r) {
		del(c[change[t].l]);
		add(change[t].r);
	}
	swap(change[t].r, c[change[t].l]);
}

int main() {
	n = read(), m = read();
	num = pow(n, 0.666);
	for (int i = 1; i <= n; ++ i) {
		c[i] = read();
		pos[i] = (i - 1) / num + 1;
	}
	for (int i = 1; i <= m; ++ i) {
		char op[5];
		scanf("%s", op);
		int l = read(), r = read();
		if (op[0] == 'Q') {
			ask[++ cnta].l = l;
			ask[cnta].r = r;
			ask[cnta].id = cnta;
			ask[cnta].t = cntc;
		}
		else {
			change[++ cntc].l = l;
			change[cntc].r = r;
		}
	}
	sort(ask + 1, ask + cnta + 1);
	int l = 0, r = -1, t = 0;
	for (int i = 1; i <= cnta; ++ i) {
		while (l < ask[i].l) {
			del(c[l ++]);
		}
		while (l > ask[i].l) {
			add(c[-- l]);
		}
		while (r < ask[i].r) {
			add(c[++ r]);
		}
		while (r > ask[i].r) {
			del(c[r --]);
		}
		while (t < ask[i].t) {
			pushup(i, ++ t);
		}
		while (t > ask[i].t) {
			pushup(i, t --);
		}
		res[ask[i].id] = ans;
	}
	for (int i = 1; i <= cnta; ++ i) {
		printf("%d\n", res[i]);
	}
	return 0;
}

作者:yifan0305

出处:https://www.cnblogs.com/yifan0305/p/17031270.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载时还请标明出处哟!

posted @   yi_fan0305  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示