数据结构题锦——树状数组
树状数组
题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。
有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入格式
一行一个正整数 nn,表示项链长度。
第二行 nn 个正整数 a_iai,表示项链中第 ii 个贝壳的种类。第三行一个整数 mm,表示 HH 询问的个数。
接下来 mm 行,每行两个整数 l,rl,r,表示询问的区间。输出格式
输出 mm 行,每行一个整数,依次表示询问对应的答案。
输入输出样例
输入 #16 1 2 3 4 3 5 3 1 2 3 5 2 6输出 #12 2 4说明/提示
【数据范围】
对于 20\%20% 的数据,1\le n,m\leq 50001≤n,m≤5000;
对于 40\%40% 的数据,1\le n,m\leq 10^51≤n,m≤105;
对于 60\%60% 的数据,1\le n,m\leq 5\times 10^51≤n,m≤5×105;
对于 100\%100% 的数据,1\le n,m,a_i \leq 10^61≤n,m,ai≤106,1\le l \le r \le n1≤l≤r≤n。本题可能需要较快的读入方式,最大数据点读入数据约 20MB
分析:
这题本来是想用莫队来做的,结果,它卡我莫队,只好用树状数组来写。
这里的st数组使用来标记出现的值的下标的。
代码:
#include <bits/stdc++.h> using namespace std; const int N = 1001115; int n, m; int w[N]; int tr[N], st[N]; int ans[N]; struct Query{ int l, r, id; bool operator< (const Query &W) const{ return r < W.r; } }q[N]; inline int rd() { int x = 0, f = 0; char c = getchar(); while (!isdigit(c)) if (c == '-') f = 1, c = getchar(); while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return f ? -x : x; } int lowbit(int x) { return x & -x; } void add(int x, int c) { for (; x <= n; x += lowbit(x)) tr[x] += c; } int ask(int x) { int res = 0; for (; x; x -= lowbit(x)) res += tr[x]; return res; } int main() { // n = rd(); scanf("%d", &n); for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]); // w[i] = rd(); // m = rd(); scanf("%d", &m); for (int i = 0; i < m; i ++ ) { // int l = rd(), r = rd(); int l,r; scanf("%d%d", &l, &r); q[i] = {l, r, i}; } sort(q, q + m); for (int i = 0, j = 1; i < m; i ++ ) { for (; j <= q[i].r; j ++ ) { if (st[w[j]]) add(st[w[j]], -1); add(j, 1); st[w[j]] = j; } ans[q[i].id] = ask(q[i].r) - ask(q[i].l - 1); } for (int i = 0; i < m; i ++ ) printf("%d\n", ans[i]); return 0; }