蒜头君的排序

蒜头君是一个爱思考的好孩子,这一天他学习了冒泡排序,于是他就想,把一个乱序排列通过冒泡排序排至升序需要多少次交换,这当然难不倒他,于是他想来点刺激的,给定一个 1 ldots n1n 的排列,每次从该排列中选择一个区间 [l,r][l,r],问使用冒泡排序将该区间排至升序需要多少次交换操作。

输入格式

第一行一个整数 nn,表示排列长度。

接下来一行 nn 个整数,表示该排列。

接下来一行一个整数 mm,表示询问次数。

接下来 mm 行,每行 22 个整数 l,rl,r,表示询问 [l,r][l,r] 区间。

输出格式

输出 mm 行,每行 11 个整数,第 ii 行表示第 ii 个询问的答案。

数据规模

对于 3030% 的数据,满足 1 le n,m le 3001n,m300;

对于 6060% 的数据,满足 1 le n,m le 10001n,m1000;

对于 100100% 的数据,满足 1 le n,m le 30000,1n,m30000l<r,l<rsum | l[i]-l[i-1] | +l[i]l[i1] sum | r[i]-r[i-1] | ler[i]r[i1]≤ 7 imes 10^67×106​​。

样例输入

10
9 8 7 4 5 6 10 3 2 1
5
2 4
8 10
2 8
5 9
4 9
 

样例输出

3
3
13
7
9
题目来源
假*题解用树状数组维护逆序对
然后我们可以从[l,r]推出[l-1,r],[l+1,r],[l,r+1],[l,r-1];
emmmmm……其实我也很迷

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,a[100100],l,r,c[100100],ll=1,lr=0,ans;
int low(int x){return x&(-x);}
void add(int x,int val){while(x<=n){c[x]+=val;x+=low(x);}}
int ask(int x){int cnt=0;while(x>0){cnt+=c[x];x-=low(x);}return cnt;}    
int main(){
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&l,&r);
        while(lr<r){
            lr++;
            ans+=ask(n)-ask(a[lr]-1);
            add(a[lr],1);
        }
        while(lr>r){
            add(a[lr],-1);
            ans-=ask(n)-ask(a[lr]-1);
            lr--;
        }
        while(ll<l){
            add(a[ll],-1);
            ans-=ask(a[ll]-1);
            ll++;
        }
        while(ll>l){
            ll--;
            ans+=ask(a[ll]-1);
            add(a[ll],1);
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/2017noipak/p/7790031.html