【数据结构专题班树状数组、线段树练习题】B [SDOI2009] HH的项链 题解
考点
树状数组
离线查询
分析
先把要查询的区间离线下来,对它们按照右边界从小到大排序,保证只需要从左至右将数组扫描一次。一边利用树状数组即时更新维护不同的元素个数,一边进行查询并保存答案,这个过程是动态的,便于我们只记录最近出现的元素的位置。即从右边界往左看,最右边已经有的数,左边再出现就可忽略不计了。这就是离线查询的原因。
AC代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1e6 + 5;
int a[maxn], n;
struct Node {
int L, R, id;
bool friend operator < (const Node &A, const Node &B) {
return A.R < B.R;
}
}ques[maxn];
int ans[maxn], last[maxn];
class Tree_array {
public:
int tree[maxn];
inline int lowbit(int x) {
return x&(-x);
}
void add(int pos, int val) {
while (pos <= n) {
tree[pos] += val;
pos += lowbit(pos);
}
}
int query(int pos) {
int sum = 0;
while (pos >= 1) {
sum += tree[pos];
pos -= lowbit(pos);
}
return sum;
}
};
int main()
{
Tree_array tra;
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)cin >> a[i];
int m;
cin >> m;
for (int i = 1; i <= m; i++) {
cin >> ques[i].L >> ques[i].R;
ques[i].id = i;
}
sort(ques + 1, ques + 1 + m);
int pos = 1;
memset(last, 0, sizeof(last));
for (int i = 1; i <= m; i++) {
for (; pos <= ques[i].R; pos++) {
if (last[a[pos]])tra.add(last[a[pos]], -1);
tra.add(pos, 1);
last[a[pos]] = pos;
}
ans[ques[i].id] = tra.query(ques[i].R) - tra.query(ques[i].L - 1);
}
for (int i = 1; i <= m; i++)cout << ans[i] << endl;
return 0;
}
查看24道真题和解析
睿联技术公司福利 62人发布