使用查询更新数组

时间:2016-04-25 10:34:58

标签: algorithm tree

最初有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);



    }
}

如何通过使用分段树或任何其他数据结构来更有效地完成此任务。

1 个答案:

答案 0 :(得分:0)

解决方案的缓慢部分是您在每次查询后重新计算哈希值(O(N * Q))。

为了加快速度,您需要尽可能多地重复使用以前的结果。 那么让我们看一下查询后哈希和会发生什么。

假设您选择位置x的学生,并将他按顺序列表移至y位置(通过提高分数)。对于哈希值:

  • y-1的部分总和保持不变(那里没有变化)。
  • x + 1之后的部分和保持不变(那里没有变化)。
  • 您需要减少x old_score并添加y new_score以考虑学生搬家。
  • 对于y和x-1之间的学生,他们成为y + 1 ... x。因此,哈希值需要增加其得分总和。

所有这些操作都可以在最多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)。您可以使用提到的部分和在二叉树中找到的最后一个总和。