这是我要解决的问题,我正在使用The Fact That Prefix Sum[i] - Prefix Sum[i-1]导致频率大于零的频率来标识不同的数字,然后消除频率,但是即使使用BIT,我也获得了标题
The Fact That Prefix Sum[i] - Prefix Sum[i-1]
给定n个数字a1,a2,…,an和多个d查询的序列。
d查询是一对(i,j)(1≤i≤j≤n)。
对于每个d查询(i,j),您必须返回子序列ai,ai + 1,…,aj中不同元素的数量。
Input Line 1: n (1 ≤ n ≤ 30000). Line 2: n numbers a1, a2, ..., an (1 ≤ ai ≤ 106). Line 3: q (1 ≤ q ≤ 200000), the number of d-queries. In the next q lines, each line contains 2 numbers i, j representing a d-query (1 ≤ i ≤ j ≤ n). Output For each d-query (i, j), print the number of distinct elements in the subsequence ai, ai+1, ..., aj in a single line. Example Input 5 1 1 2 1 3 3 1 5 2 4 3 5 Output 3 2 3
代码是:
#include <iostream> #include <algorithm> #include <vector> #include <stdlib.h> #include <stdio.h> typedef long long int ll; using namespace std; void update(ll n, ll val, vector<ll> &b); ll read(ll n,vector<ll> &b); ll readsingle(ll n,vector<ll> &b); void map(vector<ll> &a,vector<ll> &b,ll n) /**** RElative Mapping ***/ { ll temp; a.clear(); b.clear(); for(ll i=0; i<n; i++) { cin>>temp; a.push_back(temp); b.push_back(temp); } sort(b.begin(),b.end()); for(ll i=0; i<n; i++) *(a.begin()+i) = (lower_bound(b.begin(),b.end(),a[i])-b.begin())+1; b.assign(n+1,0); } int main() { ll n; cin>>n; vector<ll> a,b; map(a,b,n); ll t; cin>>t; while(t--) { ll l ,u; b.assign(n+1,0); cin>>l>>u; l--;/*** Reduce For Zero Based INdex ****/ u--; for(ll i=l;i<=u;i++) update(a[i],1,b); ll cont=0; for(ll i=l;i<=u;i++) if(readsingle(a[i],b)>0) { cont++; update(a[i],-readsingle(a[i],b),b); /***Eliminate The Frequency */ } cout<<cont<<endl; } return 0; } ll readsingle(ll n,vector<ll> &b) { return read(n,b)-read(n-1,b); } ll read(ll n,vector<ll> &b) { ll sum=0; for(; n; sum+=b[n],n-=n&-n); return sum; } void update(ll n, ll val, vector<ll> &b) { for(; n<=b.size(); b[n]+=val,n+=n&-n); }
您使用的算法太慢。对于每个查询,您都要遍历整个查询范围,而整个查询范围已经提供了n * q操作(显然,这太多了)。这是一个更好的解决方案(它具有O((n + q) * log n)时间和O(n + q)空间复杂性(这是一个脱机解决方案):
n * q
O((n + q) * log n)
O(n + q)
让我们按其右端对所有查询进行排序(无需显式对它们进行排序,您只需将查询添加到适当的位置(从0到n - 1))。
0
n - 1
现在让我们从左到右遍历数组中的所有位置并保持BIT。BIT中的每个位置要么是1(表示在位置有一个新元素i),要么是0(最初是用零填充)。
1
i
对于每个元素a[i]:如果它是该元素的第一次出现,则只需i在BIT中的位置添加一个即可。否则,将其添加-1到该元素上一次出现的位置,然后添加1到该i位置。
a[i]
-1
查询的答案(left, right)只是从left到的所有元素的总和right。
(left, right)
left
right
要维护每个元素的最后一次出现,可以使用地图。
可以使用持久性段树使其联机(时间复杂度是相同的,相同的复杂度将变为O(n * log n + q)),但是这里并不需要。
O(n * log n + q)