[SDOI2009] HH的项链
题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。
有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入格式
一行一个正整数
n
n
n,表示项链长度。
第二行
n
n
n 个正整数
a
i
a_i
ai,表示项链中第
i
i
i 个贝壳的种类。
第三行一个整数
m
m
m,表示 HH 询问的个数。
接下来
m
m
m 行,每行两个整数
l
,
r
l,r
l,r,表示询问的区间。
输出格式
输出 m m m 行,每行一个整数,依次表示询问对应的答案。
样例 #1
样例输入 #1
6
1 2 3 4 3 5
3
1 2
3 5
2 6
样例输出 #1
2
2
4
提示
【数据范围】
对于
20
%
20\%
20% 的数据,
1
≤
n
,
m
≤
5000
1\le n,m\leq 5000
1≤n,m≤5000;
对于
40
%
40\%
40% 的数据,
1
≤
n
,
m
≤
1
0
5
1\le n,m\leq 10^5
1≤n,m≤105;
对于
60
%
60\%
60% 的数据,
1
≤
n
,
m
≤
5
×
1
0
5
1\le n,m\leq 5\times 10^5
1≤n,m≤5×105;
对于
100
%
100\%
100% 的数据,
1
≤
n
,
m
,
a
i
≤
1
0
6
1\le n,m,a_i \leq 10^6
1≤n,m,ai≤106,
1
≤
l
≤
r
≤
n
1\le l \le r \le n
1≤l≤r≤n。
本题可能需要较快的读入方式,最大数据点读入数据约 20MB
原题
代码
#include <bits/stdc++.h>
using namespace std;
#define max_Heap(x) priority_queue<x, vector<x>, less<x>>
#define min_Heap(x) priority_queue<x, vector<x>, greater<x>>
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
const double PI = acos(-1);
const int maxn = 1e6 + 6;
// 主席树需记录左孩子,右孩子及节点值
struct node
{
int lc, rc, val;
} tree[maxn << 5]; // 开树节点空间
int root[maxn]; // 每一棵线段树的根节点
int idx; // 当前节点序号
int build(int st, int ed, int root, int x, int f)
{
int now_idx = ++idx; // 创建新节点
tree[now_idx] = tree[root]; // 复制根节点
tree[now_idx].val += f; // f为1则加1,f为-1则减1
if (st == ed)
return now_idx;
int mid = (st + ed) / 2; // 二分建树
if (x <= mid)
tree[now_idx].lc = build(st, mid, tree[root].lc, x, f);
else
tree[now_idx].rc = build(mid + 1, ed, tree[root].rc, x, f);
return now_idx;
}
int query(int l, int r, int st, int ed, int root2, int root1)
{
if (l <= st && r >= ed)
return tree[root2].val - tree[root1].val; // 第r棵树减去第l-1棵树即为l到r区间的个数
int mid = (st + ed) / 2;
int ans = 0;
if (l <= mid)
ans += query(l, r, st, mid, tree[root2].lc, tree[root1].lc);
if (r > mid)
ans += query(l, r, mid + 1, ed, tree[root2].rc, tree[root1].rc);
return ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
unordered_map<int, int> mp; // 存储某值上一次出现的位置,没出现时pos为0
int n, m;
cin >> n;
int tmp; // 存储读入数据
for (int i = 1; i <= n; i++) // 建第i棵线段树
{
cin >> tmp;
root[i] = build(0, n + 6, root[i - 1], mp[tmp], 1);
mp[tmp] = i; // 更新tmp的值前一次出现的位置
}
cin >> m;
int l, r;
while (m--)
{
cin >> l >> r;
cout << query(0, l - 1, 0, n + 6, root[r], root[l - 1]) << '\n';
}
return 0;
}