洛谷 SP3267 DQUERY - D-query
- 题意:给一个数列,查询一个区间中有多少个不同的数字。
- dl莫队详解【真的超级详解,很腻害的样子】
- 大致思想:典型离线算法。将所有查询区间按照左端点所在块升序,右端点升序排列。用两个指针L,R。初始化L = 1,R = 0. 用now记录当前区间不同数字的个数。然后移动两个指针,如果左指针左移,那就是添加元素;左指针右移就是删除元素。右指针与其相反。直至L、R与查询区间重合,然后更新now。
至于如何添加和删除元素以及更新now呢?我们需要一个记录元素个数的数组cnt.
添加元素时:在添加前,如果cnt为0,说明[L, R]中在添加前没有该元素,那么++now
删除元素时:删除之后,如果cnt为0,说明在删除后,[L, R]中没有改元素了,那么--now
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)
#define MID (l + r ) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define eps 1e-6
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 3e4 + 5;
const int maxq = 2e5 + 5;
inline int read()
{
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
int n, m, arr[maxN], cnt[1000006];
int block[maxN];
int l = 1, r = 0, now;
struct node{
int ql, qr, id;
node(int a = 0, int b = 0, int c = 0): ql(a), qr(b), id(c) {}
friend bool operator < (node n1, node n2) { return block[n1.ql] == block[n2.ql] ? n1.qr < n2.qr : block[n1.ql] < block[n2.ql]; }
}info[maxq];
int ans[maxq];
void add(int x)
{
if(!cnt[x]) ++now;
++ cnt[x];
}
void del(int x)
{
-- cnt[x];
if(!cnt[x]) --now;
}
int main()
{
n = read(); m = sqrt(n);
for(int i = 1; i <= n; i ++ )
{
arr[i] = read();
block[i] = (i - 1) / m + 1;
}
int q; q = read();
for(int i = 1; i <= q; i ++ )
{
int ql, qr; ql = read(); qr = read();
info[i] = node(ql, qr, i);
}
sort(info + 1, info + q + 1);
for(int i = 1; i <= q; i ++ )
{
int ql = info[i].ql, qr = info[i].qr;
while(l < ql) //左指针右移,减
del(arr[l ++ ]);
while(l > ql) //左指针左移,加
add(arr[-- l]);
while(r > qr) //右指针左移,减
del(arr[r -- ]);
while(r < qr) //右指针右移,加
add(arr[++ r]);
ans[info[i].id] = now;
}
for(int i = 1; i <= q; i ++ )
printf("%d\n", ans[i]);
return 0;
}