ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

给定一个正整数序列a,对于每次询问,输出al...ar中的逆序对数,强制在线。

Input

第一行包括一个整数n(1<=n<=50000),表示数列a中的元素数。
第二行包括n个整数a1...an(ai>0,保证ai在int内)。
接下来一行包括一个整数m(1<=m<=50000),表示询问的个数。
接下来m行,每行包括2个整数l、r(1<=l<=r<=n),表示询问al...ar中的逆序
对数(若ai>aj且i<j,则为一个逆序对)。
l,r要分别异或上一次询问的答案(lastans),最开始时lastans=0。
保证涉及的所有数在int内。

Output

对每个询问,单独输出一行,表示al...ar中的逆序对数。

分为sqrt(n)块,预处理每两块间和块内的逆序对数,以及每个位置的数到每块的逆序对数,取前缀和。

对询问合并区间内块内和块间答案,临时计算两端的答案。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,l,r,la;
int v[50005];
int v1[50005],v2[50005],v3[50005];
int ls[230],rs[230],bp=0;
int bs[230];
int bb[230][230];
int pb[230][50001];
int sz;
int cal(int l,int r){
    int m=l+r>>1,ans=0;
    if(l<m)ans+=cal(l,m);
    if(m+1<r)ans+=cal(m+1,r);
    int p1=l,p2=m+1,p3=l;
    while(p1<=m&&p2<=r){
        if(v2[p1]<=v2[p2])v3[p3++]=v2[p1++];
        else ans+=m+1-p1,v3[p3++]=v2[p2++];
    }
    while(p1<=m)v3[p3++]=v2[p1++];
    while(p2<=r)v3[p3++]=v2[p2++];
    for(int i=l;i<=r;i++)v2[i]=v3[i];
    return ans;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",v+i);
        v1[i]=v[i];
    }
    sz=sqrt(n);
    for(int i=1;i<=n;i+=sz){
        ls[bp]=i;
        rs[bp]=i+sz-1;
        if(rs[bp]>n)rs[bp]=n;
        for(int i=ls[bp];i<=rs[bp];i++)v2[i]=v[i];
        bs[bp]=cal(ls[bp],rs[bp]);
        for(int i=ls[bp];i<=rs[bp];i++)v1[i]=v2[i];
        bp++;
    }
    for(int i=0;i<bp;i++){
        for(int j=i+1;j<bp;j++){
            bb[i][j+1]+=bb[i][j];
            for(int a=rs[i],p=rs[j]+1;a>=ls[i];a--){
                while(p>ls[j]&&v1[p-1]>=v1[a])--p;
                bb[i][j+1]+=p-ls[j];
            }
        }
    }
    for(int i=0;i<bp;i++){
        for(int j=1;j<=n;j++){
            pb[i+1][j]+=pb[i][j];
            if(j<ls[i])pb[i+1][j]+=lower_bound(v1+ls[i],v1+rs[i]+1,v[j])-v1-ls[i];
            else if(j>rs[i])pb[i+1][j]+=v1+rs[i]+1-upper_bound(v1+ls[i],v1+rs[i]+1,v[j]);
        }
    }
    scanf("%d",&m);
    while(m--){
        int ans=0;
        scanf("%d%d",&l,&r);
        l^=la;r^=la;
        int lb=(l-1)/sz,rb=(r-1)/sz;
        if(lb==rb){
            for(int i=l;i<=r;i++)v2[i]=v[i];
            ans+=cal(l,r);
        }else{
            for(int i=l;i<=rs[lb];i++)v2[i]=v[i];
            if(l<rs[lb])ans+=cal(l,rs[lb]);
            for(int i=ls[rb];i<=r;i++)v2[i]=v[i];
            if(ls[rb]<r)ans+=cal(ls[rb],r);
            for(int i=rs[lb],p=r+1;i>=l;i--){
                while(p>ls[rb]&&v2[p-1]>=v2[i])--p;
                ans+=p-ls[rb];
            }
        }
        lb++;
        rb--;
        if(lb<=rb){
            for(int i=l;i<=ls[lb]-1;i++)ans+=pb[rb+1][i]-pb[lb][i];
            for(int i=rs[rb]+1;i<=r;i++)ans+=pb[rb+1][i]-pb[lb][i];
            for(int i=lb;i<=rb;i++)ans+=bs[i];
            if(lb<rb)
            for(int i=lb;i<rb;i++)
            ans+=bb[i][rb+1]-bb[i][i+1];
        }
        printf("%d\n",la=ans);
    }
    return 0;
}

 

posted on 2016-02-03 18:43  nul  阅读(402)  评论(0编辑  收藏  举报