SPOJ-DQUERY D-query 莫队算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37753409/article/details/83212319

SPOJ-DQUERY D-query 莫队算法

题意: 给定一个区间和2e5次查询, 查找区间[L, R]的不同的数的个数.
分析: 莫队和主席树都可以解决, 先离线再处理查询.
1. 莫队算法: 莫队算法一般用来处理区间查询问题, 区间必须离线, 更新操作要简单的问题. 主要做法是将区间分块, 然后根据区间的范围进行排序, 查询R节点为第一关键字, L节点为第二关键字. 排序后在进行处理, 算是一种优美的暴力, 莫队算法在处理离线区间查询问题几乎是无敌的. 对于这道题, 查询的是不同数的个数, 离线处理时就直接记录不同的数的个数就好, 算是一道模板题.
2. 主席树: 待更新.
莫队算法代码:

#include <bits/stdc++.h>

using namespace std;
const int MAXN = 1e6 + 10;
struct Query
{
    int l, r, id;
} Q[MAXN];

int n, m;
int L = 1, R = 0, Ans = 0;
int pos[MAXN], a[MAXN];
int flag[MAXN], ans[MAXN];
map<int, int> mp;
bool cmp(Query x, Query y)
{
    if (pos[x.l] == pos[y.l])
        return x.r < y.r;
    else
        return pos[x.l] < pos[y.l];
}

void add(int x)
{
    if (flag[a[x]] == 0)
        Ans++;
    flag[a[x]]++;
}
void del(int x)
{
    flag[a[x]]--;
    if (flag[a[x]] == 0)
        Ans--;
}
int main()
{
    scanf("%d", &n);
    int unit = sqrt(n);
    int sz = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        if (mp[a[i]] == 0)
        {
            mp[a[i]] = ++sz;
        }
        a[i] = mp[a[i]];
        pos[i] = i / unit + 1;
    }
    scanf("%d", &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, cmp);

    for (int i = 1; i <= m; i++)
    {
        while (L < Q[i].l)
        {
            del(L);
            L++;
        }
        while (L > Q[i].l)
        {
            L--;
            add(L);
        }
        while (R < Q[i].r)
        {
            R++;
            add(R);
        }
        while (R > Q[i].r)
        {
            del(R);
            R--;
        }
        ans[Q[i].id] = Ans;
    }

    for (int i = 1; i <= m; i++)
        printf("%d\n", ans[i]);
    return 0;
}

主席树代码:

//待更新

猜你喜欢

转载自blog.csdn.net/qq_37753409/article/details/83212319