SP3267 DQUERY - D-query(普通莫队)

题目

洛谷题目

题解

莫队板子题

  • 普通莫队的操作
  1. 将询问排序
  2. 定义L,R指针跳到询问区间
  • 排序方式
    将整个区间分为不同块,块长为 n m \frac{n}{\sqrt{m}} m n有的大佬说是 n \sqrt{n} n 但是推一下就知道 n m \frac{n}{\sqrt{m}} m n更合理
  • 指针跳动 这个应该很好理解吧
  • 跳动时答案统计方式(看代码理解吧)
    c n t [ i ] cnt[i] cnt[i]表示颜色为 i i i出现的次数
#include <bits/stdc++.h>
using namespace std; 
//const int maxn = 3e4 + 1000; 
//const int maxc = 1e6 + 1000; 
const int maxm = 5e6 + 1000; 

template <typename T>
inline void read(T &s) {
	s = 0; 
	T w = 1, ch = getchar(); 
	while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
	while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
	s *= w; 
}

int n, m, k, blo, ans; 
int a[maxm], cnt[maxm], res[maxm], belong[maxm]; 
struct query { int l, r, id; } q[maxm];

/*inline bool cmp(query aa, query bb) { 
	return (belong[aa.l] == belong[bb.l]) ? aa.r < bb.r : aa.l < bb.l; 
}*/

inline bool cmp(query aa, query bb){
	return belong[aa.l] ^ belong[bb.l] ? belong[aa.l] < belong[bb.l] : belong[aa.l] & 1 ? aa.r < bb.r : aa.r > bb.r;
}
//inline void add(int x) { if (!cnt[ a[x] ]) ans++; ++cnt[ a[x] ]; }
//inline void del(int x) { --cnt[ a[x] ]; if (!cnt[ a[x] ]) ans--; }
//inline void add(int x) { if (!cnt[ a[x] ]++) ans++; }
//inline void del(int x) { if (!--cnt[ a[x] ]) ans--; }

int main() {
	read(n);
	blo = sqrt(n); 
	for (int i = 1; i <= n; ++i)
		read(a[i]), belong[i] = (i - 1) / blo + 1;  
	read(m); 
//	blo = n / sqrt(m);
	for (int i = 1; i <= m; ++i) {
		read(q[i].l), read(q[i].r);
		q[i].id = i;  
	}
	
	sort(q + 1, q + m + 1, cmp); 
	
	int l = 1, r = 0; 
	for (int i = 1; i <= m; ++i) {
		int ql = q[i].l, qr = q[i].r; 
//		while (l < ql) del(l++); 
//		while (l > ql) add(--l); 
//		while (r > qr) del(r--); 
//		while (r < qr) add(++r); 
		
		while (l < ql) ans -= !--cnt[ a[l++] ]; 
		while (l > ql) ans += !cnt[ a[--l] ]++; 
		while (r > qr) ans -= !--cnt[ a[r--] ]; 
		while (r < qr) ans += !cnt[ a[++r] ]++; 
		res[ q[i].id ] = ans; 
	}
	for (int i = 1; i <= m; ++i) {
		printf("%d\n", res[i]); 
	}
	return 0; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值