蒜头君是一个爱思考的好孩子,这一天他学习了冒泡排序,于是他就想,把一个乱序排列通过冒泡排序排至升序需要多少次交换,这当然难不倒他,于是他想来点刺激的,给定一个 1 ldots n1…n 的排列,每次从该排列中选择一个区间 [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 3001≤n,m≤300;
对于 6060% 的数据,满足 1 le n,m le 10001≤n,m≤1000;
对于 100100% 的数据,满足 1 le n,m le 30000,1≤n,m≤30000, l<r,l<r, sum | l[i]-l[i-1] | +∑∣l[i]−l[i−1]∣ + sum | r[i]-r[i-1] | le∑∣r[i]−r[i−1]∣≤ 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; }