标签:last int SP3267 tree DQUERY MAXN rec ask query
题目大意:
给出一个长度为n 的数列,\(a_{1},a_{2},...,a_{n}\),有q 个询问,每个询问给出数对 \((i,j)\),需要你给出 \(a_{i},a_{i+1} ,...,a_j\) 这一段中有多少不同的数字
分析:
考虑到树状数组对于处理前缀和问题很方便,自然,尝试用树状数组来进行处理。设 \(tree[i]\) 表示前 \(i\) 个数不同的数的种类数。显然,这样处理是不够的。在计算的过程中,我们也要对 \(tree[i]\) 进行更新。
为了更方便地进行 \(tree[i]\) 的更新,我们将每个询问先保存下来,进行离线操作,按照 \(j\) 的由小到大的顺序进行排序。对于每个区间,尽可能统计其靠近右端点的不同的数的个数,用一个 \(last[i]\) 表示在输入序列下标为 \(i\) 的元素左边第一个值与它相同的元素的下标。对于一个数,它最后出现的位置越靠近当前枚举的右端点越好。以 \(k\) 为枚举的下标,如果 \(a[k]\) 之前有相同的数,那么减掉之前那个数的贡献,加上当前数的贡献。这样就能完成对 \(tree\) 数组的维护。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
int n,a[MAXN],tree[MAXN],rec[MAXN],last[MAXN],m,ans[MAXN];
struct askk{
int l,r,pos;
}ask[MAXN];
bool cmp(askk aa,askk b){
return aa.r < b.r;
}
int lowbit(int i){
return i & -i;
}
void add(int x,int y){
while(x <= n){
tree[x] += y;
x += lowbit(x);
}
}
int sum(int x){
int ans = 0;
while(x > 0){
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
last[i] = rec[a[i]]?rec[a[i]]:MAXN;
rec[a[i]] = i;//维护 last 数组
}
cin >> m;
for(int i = 1; i <= m; i++){
cin >> ask[i].l >> ask[i].r;
ask[i].pos = i;
}
int k = 1;
sort(ask + 1,ask +1 + m,cmp);//对询问排序
for(int i = 1; i <= m; i++){
while(k <= ask[i].r){
add(last[k],-1);
add(k,1);//维护tree数组
k++;
}
ans[ask[i].pos] = sum(ask[i].r) - sum(ask[i].l - 1);
}
for(int i = 1; i <= m; i++){
cout << ans[i] << "\n";
}
}
标签:last,int,SP3267,tree,DQUERY,MAXN,rec,ask,query 来源: https://www.cnblogs.com/CZ-9/p/16541985.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。