区间不同数
金牌导航 莫队-1
题目大意
给出n个数,然后询问m次,每次询问一个区间内不同的数的个数
样例输入
6
1 2 3 4 3 5
3
1 2
3 5
2 6
样例输出
2
2
4
数据范围
1⩽n⩽5×104,1⩽m⩽2×105,0⩽ai⩽1061\leqslant n\leqslant 5\times 10^4,1\leqslant m\leqslant 2\times 10^5,0\leqslant a_i\leqslant 10^61⩽n⩽5×104,1⩽m⩽2×105,0⩽ai⩽106
解题思路
先将原序列分块,然后对每个查询进行排序,排序以左端点所在块为第一关键字,以右端点为第二关键字
然后每次在上一个查询的前提下进行查询
分块和莫队有效降低了时间复杂度,使时间复杂度是O(nn)O(n\sqrt{n})O(nn)
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 50010
#define M 200021
#define NN 1000010
using namespace std;
int n, m, w, g, l, r, s[N], p[NN], ans[M];
struct node
{int v, b, l, r;
}a[M];
bool cmp(node a, node b)
{return a.b < b.b || a.b == b.b && a.r < b.r;
}
int main()
{scanf("%d", &n);g = sqrt(n);for (int i = 1; i <= n; ++i)scanf("%d", &s[i]);scanf("%d", &m);for (int i = 1; i <= m; ++i){scanf("%d%d", &a[i].l, &a[i].r);a[i].v = i;a[i].b = (a[i].l - 1) / g + 1;//所在块}sort(a + 1, a + 1 + m, cmp);for (int i = 1; i <= m; ++i){while(l < a[i].l) if (!--p[s[l++]]) w--;//移动指针while(l > a[i].l) if (!p[s[--l]]++) w++;while(r < a[i].r) if (!p[s[++r]]++) w++;while(r > a[i].r) if (!--p[s[r--]]) w--;ans[a[i].v] = w;}for (int i = 1; i <= m; ++i)printf("%d\n", ans[i]);return 0;
}