我有一个长度为N的对的向量。现在我有给定范围的Q个查询,让我们说L到R,找到第一个元素等于给定数K的对中第二个元素的最小值。
例如:
6个元素的向量 [{2,5},{8,7},{2,3},{8,6},{2,1},{8,4}]
现在可查询:L = 3 R = 6(基于1的索引)和K = 8
答案为-> 4,对应于这对{8,4}
Q <= 100000
N <= 100000
对<= 100000 的第一个和第二个元素的值我当时正在考虑采用段树方法,基本上是说成对的每个唯一的“第一”元素创建一个数组,其元素由原始对的“第二”元素组成,其中“第一”元素的值是v1;
现在为每个v1数组创建一个片段树,该树存储给定范围内的最小元素。
然后,我们可以简单地查询对应的“ v1”细分树以解决上述问题
我的方法很复杂,有人可以给我一个有效解决此问题的想法。
答案 0 :(得分:1)
在这种情况下,您也可以使用地图,因为您所需的输出是第二个值。因此,将第一个值作为键,将第二个值作为键。 例如在3到6(基于1的索引)的给定范围内,您的地图将被跟踪。 2-> [3,1] 8-> [6,4] 现在,代码摘录看起来像。
map<int,vector<int>> m;// my map already contains the value, i suppose you know that.
vector<int> temp;
temp=m[k];//here k=8 as given
//find the smallest element in the given array temp.
// this method give O(nlogn) complexity
sort(temp.begin(),temp.end());
cout<<temp[0];
// this method will take complexity of o(n)
int min=INT_MAX;
for(int i=0;i<temp.size();i++)
{
if(temp[i]<min)
{
min=temp[i];
}
}
cout<<min;
答案 1 :(得分:0)
使用以下公式获取输入对并从中创建三元组T
的数组:
(ai, bi) becomes ti = (ai, i, bi)
然后排序T
。计算T
上的段树,以便在知道O(log(n))
子数组的开始和结束索引时可以获取T
中第三字段的最小值。
定义常量:
int const nOO = std::numeric_limits<int>::min();
int const pOO = std::numeric_limits<int>::max();
接收查询时:(K, L, R)
。将lower_bound()
上的T
与(K, L, nOO)
一起使用,以找到T
子数组的开始,其中三元组的第一项为K
或更大,并且索引更大或等于L
。
将upper_bound()
与(K, R, pOO)
一起使用以查找子数组的结尾(不包括结尾)。
现在,您可以使用段树来了解bi
中的两个边界,以检索T
的最小值。
对于每个查询,复杂度应为O(3*log(n)) = O(log(n))
,对于O(n*log(n))
数组和段树的初始构造,应为T
。