【莫队_basic】洛谷 SP3267 DQUERY - D-query

 洛谷 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;
}
发布了182 篇原创文章 · 获赞 54 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104006671