HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。
有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入格式
一行一个正整数 n,表示项链长度。
第二行 n 个正整数 ai,表示项链中第 i 个贝壳的种类。
第三行一个整数 m,表示 H 询问的个数。
接下来 m 行,每行两个整数 l,r,表示询问的区间。
输出格式
输出 m 行,每行一个整数,依次表示询问对应的答案。
输入输出样例
输入 #1复制
6
1 2 3 4 3 5
3
1 2
3 5
2 6
输出 #1复制
2
2
4
首先考虑莫队算法,离线操作,先对询问的l进行从小到大排序,相同的r如果在相同的块内,按照从小到大排序
莫队是一种离线暴力算法,采用的分块的思想,将询问的区间按照左端点和相同块内的右端点,从小到大排序,再用类似于双指针的操作,去左移右移区间来查询
代码
#include题解(树状数组)#include #include #include #include #include #include #include #include #include #include #include #include
用树状数组的思想和莫队差不多,都是离线暴力,但是树状数组的时间复杂度更加优秀,首先把所有的询问储存进来,按找右端点从小到大进行排序后;
先不把值存进树状数组里,我们先定义一个pos,作为树状数组的下标,代表我们已经维护到了pos的位置,每次查询都更新到询问的r值,定义一个标记数组存每个数字最后一次出现的下标,每次先加上现在这个值的贡献,如果之前已经存在这个值了,再把这个值的贡献减掉,更新标记数组的值
#include题解(主席树)#define ll long long #define gcd __gcd #define endl 'n' #define mem(x, y) memset(x, y, sizeof(x)) #define inf 0x3f3f3f #define ninf 0xc0c0c0c0 #define se second #define fr first using namespace std; typedef pair PII; const int N = 1000010; int a[N]; int c[N]; int n, m; struct node { int l, r, id; bool operator<(const node &t) const { if (r == t.r) return l < t.l; else return r < t.r; } } q[N]; int lowbit(int x) { return x & -x; } void add(int i, int x) { for (; i <= n; i += lowbit(i)) c[i] += x; } int ask(int i) { int sum = 0; for (; i > 0; i -= lowbit(i)) sum += c[i]; return sum; } map p; int ans[N]; void solve() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); scanf("%d", &m); for (int i = 1; i <= m; i++) { int l, r, id; scanf("%d%d", &l, &r); q[i] = {l, r, i}; } sort(q + 1, q + m + 1); int pos = 0; for (int i = 1; i <= m; i++) { int l = q[i].l, r = q[i].r, idx = q[i].id; while (pos + 1 <= r) { pos++; add(pos, 1); if (p[a[pos]]) add(p[a[pos]], -1); p[a[pos]] = pos; } ans[idx] = ask(r) - ask(l - 1); } for (int i = 1; i <= m; i++) { printf("%dn", ans[i]); } } signed main() { solve(); }
后续更新。。。



