SP3267 DQUERY - D-query

题目大意:

给出一个长度为n 的数列,a1,a2,...,an,有q 个询问,每个询问给出数对 (i,j),需要你给出 ai,ai+1...aj 这一段中有多少不同的数字

分析:

考虑到树状数组对于处理前缀和问题很方便,自然,尝试用树状数组来进行处理。设 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"; } }

__EOF__

本文作者Never Gonna Give You Up!
本文链接https://www.cnblogs.com/CZ-9/p/16541985.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   腾云今天首飞了吗  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示