版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}
主席树代码:
//待更新