2492. HH的项链

题目链接

2492. HH的项链

HH 有一串由各种漂亮的贝壳组成的项链。

HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。

HH 不断地收集新的贝壳,因此他的项链变得越来越长。

有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?

这个问题很难回答,因为项链实在是太长了。

于是,他只好求助睿智的你,来解决这个问题。

输入格式

第一行:一个整数 \(N\),表示项链的长度。

第二行:\(N\) 个整数,表示依次表示项链中贝壳的编号(编号为 \(0\)\(1000000\) 之间的整数)。

第三行:一个整数 \(M\),表示 HH 询问的个数。

接下来 \(M\) 行:每行两个整数,\(L\)\(R\),表示询问的区间。

输出格式

\(M\) 行,每行一个整数,依次表示询问对应的答案。

数据范围

\(1 \le N \le 50000\),
\(1 \le M \le 2 \times 10^5\),
\(1 \le L \le R \le N\)

输入样例:

6
1 2 3 4 3 5
3
1 2
3 5
2 6

输出样例:

2
2
4

解题思路

莫队

莫队是一种离线做法,核心思想是分块+暴力

先考虑暴力做法:记录一个 \(cnt[x]\) 数组,表示当前区间 \(x\) 出现的次数,在两个区间转移时,即左右指针分别移动到对应区间的同时更新 \(cnt[x]\),同时更新答案
分块策略:将所有区间按左端点分块,同时块内的区间右端点排序再暴力求解

复杂度证明:假设块的大小为 \(len\),块内右端点由于有序,一个块内右指针移动的复杂度为 \(O(n)\),则总复杂度为 \(O(n\times \frac{n}{len})\),左指针对于每个块内的每个左指针移动的复杂度无论是在块内还是块间移动的复杂度都为 \(O(len)\),则总复杂度为 \(O(m\times len)\),令 \(n\times \frac{n}{len}=m\times len\),即 \(len=\sqrt{\frac{n^2}{m}}\),则:

  • 时间复杂度:\(n\sqrt{m}\)

代码

// Problem: HH的项链
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2494/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}
const int N=2e5+5,M=5e4+5;
int n,m,a[M],len,cnt[1000005],res[N];
struct Q
{
	int id,l,r;
}q[N];
int get(int x)
{
	return x/len;
}
void add(int x,int &res)
{
	if(!cnt[x])res++;
	cnt[x]++;
}
void del(int x,int &res)
{
	cnt[x]--;
	if(!cnt[x])res--;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    scanf("%d",&m);
    len=max(1,int(sqrt((double)n*n/m)));
    for(int i=1;i<=m;i++)scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    sort(q+1,q+1+m,[](auto &a,auto &b){
    	int i=get(a.l),j=get(b.l);
    	if(i!=j)return i<j;
    	else if(i&1)return a.r<b.r;
    	return a.r>b.r;
    });
    for(int k=1,i=0,j=1,t=0;k<=m;k++)
    {
    	int l=q[k].l,r=q[k].r;
    	while(i<r)add(a[++i],t);
    	while(i>r)del(a[i--],t);
    	while(j<l)del(a[j++],t);
    	while(j>l)add(a[--j],t);
    	res[q[k].id]=t;
    }
    for(int i=1;i<=m;i++)printf("%d\n",res[i]);
    return 0;
}
posted @ 2022-08-19 01:07  zyy2001  阅读(47)  评论(0编辑  收藏  举报