最初有N
名学生都有0分。现在我们在每个查询中提供Q
查询,我们会增加A index students by B
的标记。现在重新安排学生我增加等级,即最高分数将是一,第二高最高等等... ...
对于每个学生,他或她的位置等于有更多分数的学生人数,增加1。
让我们将hash of participant
定义为他/她的位置和积分数的乘积。在每次查询后,找到参与者哈希的sum
例如:
N=4 Q=4
3 100
2 60
1 80
2 20
1 20
After the first query, participant 3 has 100 and is 1, with hash equal to
100. The sum of hashes is 100+0+0+0=100
After the second query, participant 2 has the second place with 60 and hash
120, in total 100+120+0+0 = 220
After the third query, the Rank looks like follows:
(100,80,60,0). The sum of hashes is 200+160+180+0= 440
In the fourth query participant the rank is (100,80,80,0) then, with the sum
100⋅1+80⋅2+80⋅2+0⋅4=420.
我们怎样才能有效地做到这一点简单的approch在这里找到索引并替换它:
while(Q>0){
Q--;
int a = in.nextInt()-1;
long b = in.nextInt();
if(score.size()==0){
score.add(b);
A[a]=b;
System.out.println(b);
}else{
int index =-1;
if(A[a]!=0){
int s =0;
int e = score.size()-1;
while(s<=e){
int mid = (s+e)/2;
if(score.get(mid)==A[a]){
index = mid;
break;
}else if(score.get(mid)>A[a]) s = mid+1;
else e = mid-1;
}
}
A[a]+=b;
int replace= score.size();
int s =0;
int e = score.size()-1;
while(s<=e){
int mid = (s+e)/2;
if(score.get(mid)>A[a]) s = mid+1;
else{
replace = mid;
e = mid-1;
}
}
score.add(replace,A[a]);
if(index!=-1) score.remove(index+1);
long o= score.get(0);
long prev =1;
for(int i=1;i<score.size();i++){
if(score.get(i)!=score.get(i-1)){
prev =i+1;
o+=score.get(i)*prev;
}else o+=score.get(i)*(prev);
}
System.out.println(o);
}
}
如何通过使用分段树或任何其他数据结构来更有效地完成此任务。
答案 0 :(得分:0)
解决方案的缓慢部分是您在每次查询后重新计算哈希值(O(N * Q))。
为了加快速度,您需要尽可能多地重复使用以前的结果。 那么让我们看一下查询后哈希和会发生什么。
假设您选择位置x
的学生,并将他按顺序列表移至y
位置(通过提高分数)。对于哈希值:
所有这些操作都可以在最多O(logN)下完成,以将总体复杂性降低到O(QlogN)(更好)。
因此,您需要一种数据结构,允许您插入,删除和计算O(logN)或更好的部分和。我会建议一个平衡的二叉树(或跳过列表)。每个节点应该跟踪下面有多少节点以及它们的分数总和。要找到第x个元素,您可以使用节点数并找到可以使用部分和的总和。
使用此树,您无需更改节点的索引(当您在其前面插入某些内容时,它们会自动更改)。如果你想用分段树做这件事,你需要很多小心因为移动节点。
示例:
说当前的分数状态看起来像[100, 90, 80, 70, 60, 50, 40, 30]
。下一个查询是5 35
所以我们找到了第五个元素(得分为60的元素,您可以使用节点下面的元素数量来指导您的搜索)并将其增加35。将是95所以它进入第二个位置(你通过在二叉搜索树中查找值找到它)。所以x是5,y是2. hashsum更新是hashsum += 95 * 2 - 60 * 5 + (90+80+70)
。您可以使用提到的部分和在二叉树中找到的最后一个总和。