最佳数据结构支持范围Sum和连续元素交换操作?

时间:2015-01-14 10:00:42

标签: algorithm data-structures

我们有一组n正整数和m quires。 每个查询可以是以下两种类型之一。

  1. 查找某个范围[i, j]
  2. 之间所有元素的总和
  3. 对范围[i, j]中给出的元素重新排序,使得数组元素将是这样的
  4. (a[i+1],a[i],a[i+3],a[i+2],..............,a[j],a[j-1])假设这个范围长度是均匀的。其中a[i]i索引处的数组元素。

    以下是限制

    2 ≤ n,m ≤ 2×10^5 
    
    1 ≤ a[i] ≤ 10^6 
    
    1≤ i ≤ j ≤n
    

    我尝试使用细分树,但这些时间超过2秒。 任何人都可以建议最佳数据结构或任何最佳方法吗?

    这是我的代码

    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int sgtree[524288];
    int data[200005];
    int treeind[200005];
    int constructSgTree(int start,int end,int index){
        if(start==end){
            sgtree[index]=data[start];
            treeind[start]=index;
            return data[start];
        }
        else{
            int mid=start+(end-start)/2;
            sgtree[index]=constructSgTree(start,mid,index*2+1)+constructSgTree(mid+1,end,index*2+2);
            return sgtree[index];
        }
    }
    int sumSgTree(int start,int end,int i,int j,int index){
        if(i<=start&&j>=end){
            return sgtree[index];
        }
        else if(i>end||j<start){
            return 0;
        }
        else{
                int mid=start+(end-start)/2;
                return sumSgTree(start,mid,i,j,2*index+1)+sumSgTree(mid+1,end,i,j,2*index+2);
        }
    }
    void updateSgTree(int start,int end,int i,int val,int index){
    
        if(i<start||i>end){
            return ;
        }
        else{
            sgtree[index]+=val;
            if(start!=end)
            {
            int mid=start+(end-start)/2;
    
            updateSgTree(start,mid,i,val,2*index+1);
    
            updateSgTree(mid+1,end,i,val,2*index+2);
                }
    
        }
    
    
    
    
    }
    
    int main() {
        int n,i,q,op,l,r,temp,j,temp1,temp2,temp3;
        cin>>n>>q;
        float sum=0;
        for(i=0;i<n;i++){
            cin>>data[i];
            //dataind[i]=i;
        }
        constructSgTree(0,n-1,0);
        /*
        for(i=0;i<n;i++){
            cout<<sgtree[treeind[i]]<<" ";
        }
        */
        //cout<<endl;
        for(i=0;i<q;i++){
            cin>>op>>l>>r;
            l--;
            r--;
            if(op==2){
                j=l;
                /*
                sum=0.0;
                while(j<=r){
                    /*
                    temp=data[j]-sgtree[treeind[j]];
                    if(temp!=0){
                        updateSgTree(0,n-1,j,temp,0);
                    }
    
                    sum+=data[j];
                    j++;
    
                }
                cout<<sum<<endl;
             */
                cout<<sumSgTree(0,n-1,l,r,0)<<endl;
            }
            else{
                while(l<=r){
    
                    //temp=data[l+1]-data[l];
                    if(l!=r){
                        temp=sgtree[treeind[l]];
                    sgtree[treeind[l]]=sgtree[treeind[l+1]];
                    sgtree[treeind[l+1]]=temp;
                    temp1=(treeind[l]-1)/2;
                    temp2=(treeind[l+1]-1)/2;
    
    
    
                        while(temp1!=temp2){
                            if(temp1<temp2){
                                sgtree[temp2]=sgtree[temp2]+data[l]-data[l+1];
                                temp2=(temp2-1)/2;
                            }
                            else{
                                sgtree[temp1]=sgtree[temp1]-data[l]+data[l+1];
                                temp1=(temp1-1)/2;
                            }
                        }
                        //updateSgTree(0,n-1,l,temp,0);
                        //updateSgTree(0,n-1,l+1,-temp,0);
    
                    /*
                    temp=data[l];
                    data[l]=data[l+1];
                    data[l+1]=temp;
                    */
                    temp=data[l];
                    data[l]=data[l+1];
                    data[l+1]=temp; 
                    }
    
                    l+=2;   
                }
            }
        }
        return 0;
    }
    

1 个答案:

答案 0 :(得分:3)

每个查询的解决方案的时间复杂度至少为O(n)(可能是O(n log n)),因此显然太慢了。

以下是每个查询需要O(log n)时间的解决方案:

  1. 使用隐式键构建treape:第一个将包含具有偶数索引的所有元素,第二个将包含具有奇数索引的所有元素。两个树都应该根据给定数组中的索引对元素进行排序。

  2. 求和查询非常简单:我们知道范围内的最小和最大奇数和偶数索引,因此我们可以在第一个和第二个树上运行此查询并返回总和。

  3. 可以通过以下方式处理交换查询:让我们将第一个树拆分为L1, M1, R1个部分,将第二个树拆分为L2, M2, R2(其中M1 M2是查询范围内的部分。然后我们应该交换M1M2并合并树,也就是说,第一棵树是合并L1, M2, R1的结果,第二棵树是L2, M1, R2

  4. 每个查询都需要恒定数量的合并和拆分操作,因此总时间复杂度为O((n + m) * log n)O(n + m * log n)(这取决于我们在回答查询之前构建这些treaps的方式)。