假设最初在数组a
中每个元素都有无穷大作为值。
现在M
类型的l
r
x
l
类型的查询已输入。
此处r
到a[i]>x
是l<=i<=r
l<=r<=n
和M
所需的值更新范围。
在memset(a,inf,sizeof(a));
while(j<m)
{
scanf("%d %d %d",&l,&r,&c);
for(i=l-1;i<r;i++)
{
if(a[i]>c)
a[i]=c;
}
j++;
}
for(i=0;i<n;i++)
printf("%d",a[i]);
次查询后,您需要输出每个索引的最小值。
一种方法是使用暴力
var response: AnyObject = prefs.objectForKey("response")!
response = response.stringByReplacingOccurrencesOfString("-", withString: "\n")
msglbl.numberOfLines = 0;
msglbl.text = "\(response)"
msglbl.textAlignment = .Center;
msglbl.sizeToFit()
self.view.addSubview(msglbl)
msglbl.font = UIFont(name: "Gotham-Book", size: 16)
现在这需要O(mn)时间,其中n =每个查询的大小,在最坏的情况下可以是n。
在较短的时间复杂度下,有哪些更有效的方法可以解决这个问题?
答案 0 :(得分:1)
注意:我的回答是假设问题在线,因此您必须在到达时执行更新和查询。这样做的一个优点是我的解决方案更加强大,允许您以相同的复杂性添加更多类型的更新和查询。缺点是,如果您正在处理离线问题,它可能不是您问题的绝对最佳选择。
您可以使用segment tree。让段树中的每个节点存储为其关联间隔设置的最小值(最初为无穷大,非常大)并使用延迟更新和查询方案。
更新(左,右,c)
Update(node, left, right, c):
if node.interval does not intersect [left, right]:
return
if node.interval included in [left, right]:
node.minimum = min(c, node.minimum)
return
Update(node.left, left, right, c)
Update(node.right, left, right, c)
<强>查询(指数)强>
Query(node, minimum = infinity, index):
if node.interval == [index, index]:
return minimum
if index included in node.left.interval:
return Query(node.left, min(minimum, node.minimum), index)
return Query(node.right, min(minimum, node.minimum), index)
每次更新和查询操作的总复杂度:O(log n)
。您需要为最后的每个元素调用Query
。
答案 1 :(得分:1)
有一种方法具有不同的渐近复杂度。它涉及保留查询开始和结束的排序列表。为了避免实际排序,我使用了大小为a
的稀疏数组。
现在,一般的想法是你存储查询,在迭代时你保持一个包含查询的堆是你的范围:
# size of array (n)
count = ...
# for each array element you have a list of ranges that
# start or end at this array element
list<queries> l[count]
list<queries> r[count]
heap<queries> h
for i in range(count):
if l[i]:
h.push(l[i])
if h is empty:
output(inf)
else:
output(h.lowest().value)
if r[i]:
h.pop(r[i])
这个(以及其他算法)的实际性能在很大程度上取决于数组的大小和查询的密度,但这些算法的渐近复杂性都没有涵盖。在忽略实际输入数据的同时,无法找到最佳算法。根据数据改变算法也是值得的。