蒜头君是一个爱思考的好孩子,这一天他学习了冒泡排序,于是他就想,把一个乱序排列通过冒泡排序排至升序需要多少次交换,这当然难不倒他,于是他想来点刺激的,给定一个 1…n 的排列,每次从该排列中选择一个区间 [l,r],问使用冒泡排序将该区间排至升序需要多少次交换操作。
输入格式
第一行一个整数 n,表示排列长度。
接下来一行 n 个整数,表示该排列。
接下来一行一个整数 m,表示询问次数。
接下来 m 行,每行 2 个整数 l,r,表示询问 [l,r] 区间。
输出格式
输出 m 行,每行 1 个整数,第 i 行表示第 i 个询问的答案。
数据规模
对于 30% 的数据,满足 1≤n,m≤300;
对于 60% 的数据,满足 1≤n,m≤1000;
对于 100% 的数据,满足 1≤n,m≤30000, l<r, ∑∣l[i]−l[i−1]∣ + ∑∣r[i]−r[i−1]∣≤ 7×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
题目来源
#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\n",ans);
}
return 0;
}