【bzoj 3744】Gty的妹子序列(分塊+樹狀數組)

傳送門biu~
默認按size=n 分塊(求導個屁)。對於每個詢問,有三個部分:
①對於大塊之間形成的逆序對,
因爲求長度爲n的序列的逆序對數可以用樹狀數組在O(nlogn) 的時間複雜度內完成,所以可以在O(nnlogn) 的複雜度內預處理ani,j 表示塊i ~j 的逆序對數。在O(1) 的時間複雜度內詢問。
②對於零散的部分和大塊形成的逆序對,
O(nn) 的複雜度內預處理Loweri,j 代表第i ~第n 塊中小於j的數有多少個,Upperi,j 代表第1 ~i 塊中小於j的數有多少個。因爲零散部分的熟練不超過n ,所以可以在O(n) 的時間複雜度內詢問。
③對於零散的部分之間形成的逆序對,
用樹狀數組直接計算逆序對數,因爲零散部分的熟練不超過n ,所以可以在O(nlogn) 的時間複雜度內計算。
綜上,時間複雜度最大爲O(Tnlogn)

#include<bits/stdc++.h>
#define N 50005
using namespace std;
int n,m,ans,a[N],b[N],BIT[N],t[N],tim,block[N],blocksize;
int an[233][233],Lower[233][N],Upper[233][N];
inline void add(int x){
    for(int i=x;i<=m;i+=i&-i){
        if(tim^t[i])    t[i]=tim,BIT[i]=0;
        ++BIT[i];
    }
}
inline int search(int x){
    int res(0);
    for(int i=x;i;i-=i&-i){
        if(tim^t[i])    t[i]=tim,BIT[i]=0;
        res+=BIT[i];
    }   
    return res;
}
inline void init(){
    scanf("%d",&n);blocksize=sqrt(n);
    for(int i=1;i<=n;++i)   scanf("%d",&a[i]),b[i]=a[i],block[i]=(i-1)/blocksize+1;
    sort(b+1,b+n+1); m=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;++i){
        a[i]=lower_bound(b+1,b+m+1,a[i])-b;
        ++Lower[block[i]][a[i]+1],++Upper[block[i]][a[i]-1];
    }
    for(int i=1;i<=block[n];++i){
        for(int j=1;j<=m;++j)   Lower[i][j]+=Lower[i][j-1];
        for(int j=m;j>=1;--j)   Upper[i][j]+=Upper[i][j+1];     
    }
    for(int j=1;j<=m;++j){
        for(int i=block[n];i>=1;--i)    Lower[i][j]+=Lower[i+1][j];
        for(int i=1;i<=block[n];++i)    Upper[i][j]+=Upper[i-1][j];
    }
    for(int i=1;i<=block[n];++i){
        ++tim;
        for(int now=0,j=(i-1)*blocksize+1;j<=n;++j){
            now+=search(m)-search(a[j]);
            if(block[j]^block[j+1]) an[i][block[j]]=now;
            add(a[j]);
        }
    }
}
inline void solve(){
    int T,l,r;
    scanf("%d",&T);
    while(T--){
        ++tim;
        scanf("%d%d",&l,&r);
        l^=ans,r^=ans,ans=0;
        if(block[r]-block[l]<=1){
            for(int i=l;i<=r;++i)
                ans+=search(m)-search(a[i]),add(a[i]);
        }
        else{
            ans=an[block[l]+1][block[r]-1];
            for(int i=l;block[i]==block[l];++i){
                ans+=Lower[block[i]+1][a[i]]-Lower[block[r]][a[i]];
                ans+=search(m)-search(a[i]),add(a[i]);
            }
            for(int i=(block[r]-1)*blocksize+1;i<=r;++i){
                ans+=Upper[block[i]-1][a[i]]-Upper[block[l]][a[i]];
                ans+=search(m)-search(a[i]),add(a[i]);
            }
        }
        printf("%d\n",ans);
    }
}
int main(){
    init();
    solve();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章