C++ 在子数组中查找多个查询的不同(唯一)值的数目
我有一个数组(可以有2X10^5个值)。我想在此数组上执行大量查询。每个查询都属于[L,R]类型,此查询的结果应该是子数组中从索引L开始到索引R结束的唯一值的数量 我知道这可以在O(nrootn)时间内使用Mo算法完成。然而,问题是莫的算法是离线算法。我要寻找的是一个在线算法,因为前一个查询的结果决定了我案例中的下一个查询C++ 在子数组中查找多个查询的不同(唯一)值的数目,c++,arrays,algorithm,data-structures,wavelet,C++,Arrays,Algorithm,Data Structures,Wavelet,我有一个数组(可以有2X10^5个值)。我想在此数组上执行大量查询。每个查询都属于[L,R]类型,此查询的结果应该是子数组中从索引L开始到索引R结束的唯一值的数量 我知道这可以在O(nrootn)时间内使用Mo算法完成。然而,问题是莫的算法是离线算法。我要寻找的是一个在线算法,因为前一个查询的结果决定了我案例中的下一个查询 我尝试使用来形成一个段树,其中节点将存储范围中所有不同的元素。然而,这对我来说太慢了。预处理过程占用了太多的时间。 < P>这是我的C++尝试,在一个解决方案(也张贴)中使用
我尝试使用来形成一个段树,其中节点将存储范围中所有不同的元素。然而,这对我来说太慢了。预处理过程占用了太多的时间。 < P>这是我的C++尝试,在一个解决方案(也张贴)中使用了一个用代码实现的。重新表述问题(作为光子链接)的想法是首先构造一个数组,为原始数组中的每个对应单元列出右侧下一个重复元素的索引。然后问题就变成了找出区间中有多少个单元具有超出当前区间的“下一个索引”(那些在区间内显然没有重复项),这可以通过修饰的小波树来查询。请参阅底部的(非零基)查询示例
// Adapted from https://www.geeksforgeeks.org/wavelet-trees-introduction
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <climits>
using namespace std;
// wavelet tree class
class wavelet_tree {
public:
// Range to elements
int low, high;
// Left and Right child
wavelet_tree* l, *r;
std::vector<int> freq;
// Default constructor
// Array is in range [x, y]
// Indices are in range [from, to]
wavelet_tree(int* from, int* to, int x, int y)
{
// Initialising low and high
low = x, high = y;
// Array is of 0 length
if (from >= to)
return;
// Array is homogenous
// Example : 1 1 1 1 1
if (high == low) {
// Assigning storage to freq array
freq.reserve(to - from + 1);
// Initialising the Freq array
freq.push_back(0);
// Assigning values
for (auto it = from; it != to; it++)
// freq will be increasing as there'll
// be no further sub-tree
freq.push_back(freq.back() + 1);
return;
}
// Computing mid
int mid = (low + high) / 2;
// Lambda function to check if a number
// is less than or equal to mid
auto lessThanMid = [mid](int x) {
return x <= mid;
};
// Assigning storage to freq array
freq.reserve(to - from + 1);
// Initialising the freq array
freq.push_back(0);
// Assigning value to freq array
for (auto it = from; it != to; it++)
// If lessThanMid returns 1(true), we add
// 1 to previous entry. Otherwise, we add 0
// (element goes to right sub-tree)
freq.push_back(freq.back() + lessThanMid(*it));
// std::stable_partition partitions the array w.r.t Mid
auto pivot = std::stable_partition(from, to, lessThanMid);
// Left sub-tree's object
l = new wavelet_tree(from, pivot, low, mid);
// Right sub-tree's object
r = new wavelet_tree(pivot, to, mid + 1, high);
}
// Count of numbers in range[L..R] less than
// or equal to k
int kOrLess(int l, int r, int k)
{
// No elements int range is less than k
if (l > r or k < low)
return 0;
// All elements in the range are less than k
if (high <= k)
return r - l + 1;
// Computing LtCount and RtCount
int LtCount = freq[l - 1];
int RtCount = freq[r];
// Answer is (no. of element <= k) in
// left + (those <= k) in right
return (this->l->kOrLess(LtCount + 1, RtCount, k) +
this->r->kOrLess(l - LtCount, r - RtCount, k));
}
// Count of numbers in range[L..R] greater than
// or equal to k
int kOrMore(int l, int r, int k)
{
// No elements int range are greater than k
if (l > r or k > high)
return 0;
// All elements in the range are greater than k
if (low >= k)
return r - l + 1;
// Computing LtCount and RtCount
int LtCount = freq[l - 1];
int RtCount = freq[r];
// Answer is (no. of element <= k) in
// left + (those <= k) in right
return (this->l->kOrMore(LtCount + 1, RtCount, k) +
this->r->kOrMore(l - LtCount, r - RtCount, k));
}
};
int main()
{
int size = 7, high = INT_MIN;
int arr[] = {1, 2, 3, 2, 4, 3, 1};
int next[size];
std::map<int, int> next_idx;
for (int i=size-1; i>=0; i--){
if (next_idx.find(arr[i]) == next_idx.end())
next[i] = size + 1;
else
next[i] = next_idx[arr[i]];
next_idx[arr[i]] = i + 1;
high = max(high, next[i]);
}
// Object of class wavelet tree
wavelet_tree obj(next, next + size, 1, high);
// Queries are NON-zero-based
//
// 1 2 3 4 5 6 7
// {1, 2, 3, 2, 4, 3, 1};
// query([3, 6]) = 3;
cout << obj.kOrMore(3, 6, 7) << '\n';
// query([1, 4]) = 3;
cout << obj.kOrMore(1, 4, 5) << '\n';
// query([1, 7]) = 4;
cout << obj.kOrMore(1, 7, 8) << '\n';
return 0;
}
//改编自https://www.geeksforgeeks.org/wavelet-trees-introduction
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
//小波树类
类小波树{
公众:
//元素范围
int低,高;
//左右儿童
小波树*l,*r;
std::矢量频率;
//默认构造函数
//数组在范围[x,y]内
//指数的范围为[从,到]
小波树(int*from,int*to,int x,int y)
{
//初始化低和高
低=x,高=y;
//数组的长度为0
如果(从>=到)
返回;
//数组是同质的
//示例:1
如果(高==低){
//将存储分配给freq数组
频率储备(至-自+1);
//初始化Freq数组
频率推回(0);
//赋值
for(自动it=from;it!=to;it++)
//频率将随着时间的推移而增加
//不再是子树
频率回推(频率回推()+1);
返回;
}
//计算媒体
int mid=(低+高)/2;
//Lambda函数,用于检查数字
//小于或等于中间值
自动lessThanMid=[mid](int x){
返回x r或k<低)
返回0;
//范围内的所有元素都小于k
if(高r->kOrLess(l-LtCount,r-RtCount,k));
}
//范围[L..R]中大于的数字计数
//或等于k
内特科莫尔(内特l,内特r,内特k)
{
//没有元素int范围大于k
如果(l>r或k>high)
返回0;
//范围内的所有元素都大于k
如果(低>=k)
返回r-l+1;
//计算LtCount和RtCount
int LtCount=freq[l-1];
int RtCount=频率[r];
//答案是(元素kOrMore的编号(LtCount+1,RtCount,k)+
这个->r->科尔莫(l-LtCount,r-RtCount,k));
}
};
int main()
{
int size=7,high=int_MIN;
int arr[]={1,2,3,2,4,3,1};
int next[大小];
std::map next_idx;
对于(int i=size-1;i>=0;i--){
if(next_idx.find(arr[i])==next_idx.end())
下一个[i]=大小+1;
其他的
next[i]=next_idx[arr[i]];
下一个_idx[arr[i]]=i+1;
高=最大值(高,下一个[i]);
}
//类对象小波树
小波树obj(下一个,下一个+大小,1,高);
//查询不是基于零的
//
// 1 2 3 4 5 6 7
// {1, 2, 3, 2, 4, 3, 1};
//查询([3,6])=3;
无法将子数组复制到a并获取其大小?我知道这是显而易见的事情。但我有多达10^5个查询。因此这将使其成为O(n^2)。我想知道是否有一种方法可以在不到该值的情况下完成此操作。您执行这么多“查询”的时间单位是多少?每秒?每分钟?程序生命周期?听起来可能不太好,但如果这些查询延长到运行时数小时,则可能不是问题。在没有实际测量和分析的情况下,不要忽略这些明显的(可能是“糟糕的”)解决方案。“足够好了”通常已经足够好了。上一个查询的结果决定下一个查询
-如何?是否有任何规则定义它?如果没有它,将很难进行优化