蒜头君的排序

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

输入格式

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

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

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

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

输出格式

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

数据规模

样例输入

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
题解:
动态维护的树状数组
一开始很纠结到底怎么动态维护逆序对,之后看了数据才恍然大悟

最后一个范围意思就是左右端点的变化量<=7*10^6

这样连莫队都不需要了,直接左右端点移动就行了

区间[l,r]很容易堆出区间[l-1,r],[l+1,r],[l,r-1],[l,r+1]

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 int c[300001],a[300001],rpos=0,lpos=1,n,m,ans;
 7 void add(int x,int d)
 8 {
 9     while (x<=n)
10     {
11         c[x]+=d;
12         x+=(x&(-x));
13     }
14 }
15 int query(int x)
16 {
17     int s=0;
18     while (x)
19     {
20         s+=c[x];
21         x-=(x&(-x));
22     }
23     return s;
24 }
25 int main()
26 {int i,j,l,r;
27     cin>>n;
28     for (i=1;i<=n;i++)
29     {
30         scanf("%d",&a[i]);
31     }
32     cin>>m;
33      for (i=1;i<=m;i++)
34      {
35          scanf("%d%d",&l,&r);
36           while (rpos<r)
37           {
38             rpos++;
39             ans+=query(n)-query(a[rpos]-1);
40               add(a[rpos],1);
41          }
42          while (rpos>r)
43          {    
44             add(a[rpos],-1);
45              ans-=query(n)-query(a[rpos]-1);
46              rpos--;
47          }
48          while (lpos<l)
49          {
50          add(a[lpos],-1);
51              ans-=query(a[lpos]-1);         
52              lpos++;
53          }
54          while (lpos>l)
55          {
56              lpos--;
57              ans+=query(a[lpos]-1);
58              add(a[lpos],1);
59          }
60          printf("%d\n",ans);
61      }
62 }

 

posted @ 2017-07-30 18:36  Z-Y-Y-S  阅读(588)  评论(0编辑  收藏  举报