计蒜客D2T2 蒜头君的排序(动态维护树状数组)

Posted Slager_Z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计蒜客D2T2 蒜头君的排序(动态维护树状数组)相关的知识,希望对你有一定的参考价值。

蒜头君的排序(sort)

2000ms 262144K

蒜头君是一个爱思考的好孩子,这一天他学习了冒泡排序,于是他就想,把一个乱序排列通过冒泡排序排至升序需要多少次交换,这当然难不倒他,于是他想来点刺激的,给定一个1…n1的排列,每次从该排列中选择一个区间[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<r,∑∣l[i]?l[i?1]|+∑∣r[i]?r[i?1]∣≤ 7*10^6??。

样例输入

样例输入

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

 

解析:这道题直接暴力(直接用冒泡排序或归并排序记录逆序对)可以拿60分;

   离线使用树状数组维护能得70分;

   在线维护树状数组可以拿100分。。。(为什么离线会超时。。)

关于树状数组的维护我们可以先定义两个指针分别指向左端点和右端点,每次查询时不断的维护这段区间(左端点,右端点不断的向左向右移),即可查询到所有的答案(好神奇。。)

十分不解为什么不能先按照左端点的位置排序,后维护,这样可以少进行一个左端点向左的步骤。。可惜会超时;

关于如何从[l,r]变成[l-1,r],[l+1,r],[l,r-1],[l,r+1],自己手动模拟一遍就知道了,第一次感觉好玄学。。。

 

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #define lo(x) (x&(-x))
 6 #define ll long long
 7 #define man 30010
 8 using namespace std;
 9 //common
10 int n,m,c[man],pos[man],ask[man];
11 ll a[man],b[man];
12 inline int read()
13 {    int x=0;bool f=0;
14     char ch=getchar();
15     while(ch<0||ch>9){f=(ch==45);ch=getchar();}
16     while(ch>=0&&ch<=9){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
17     return f?(~x+1):x;
18     }
19 struct range
20 {    int x,y,id;}e[man];
21 //lowbit
22 inline void add(int x,int val)
23 {    while(x<=n)
24     {    c[x]+=val;
25         x+=lo(x);
26         }
27     return ;
28     }
29 inline int calc(int x)
30 {    int ans=0;
31     while(x>0)
32     {    ans+=c[x];
33         x-=lo(x);
34         }
35     return ans;
36     }
37 int main()
38 {    freopen("sort.in","r",stdin);
39     freopen("sort.out","w",stdout);
40     n=read();
41     for(int i=1;i<=n;i++)
42         scanf("%lld",&a[i]),b[i]=a[i];
43     sort(a+1,a+1+n);
44     for(int i=1;i<=n;i++)
45         pos[i]=lower_bound(a+1,a+n+1,b[i])-a;
46     m=read();
47     for(int i=1;i<=m;i++)
48     {    e[i].x=read();e[i].y=read();e[i].id=i;}
49     int l=1,r=0,ans=0;
50     for(int i=1;i<=m;i++)
51     {    while(r<e[i].y)
52         {    r++;
53             ans+=calc(n)-calc(pos[r]-1);
54             add(pos[r],1);
55             }
56         while(l<e[i].x)
57         {    add(pos[l],-1);
58             ans-=calc(pos[l]-1);
59             l++;
60             }
61         while(r>e[i].y)
62         {    add(pos[r],-1);
63             ans-=calc(n)-calc(pos[r]-1);
64             r--;}
65         while(l>e[i].x)
66         {    l--;
67             ans+=calc(pos[l]-1);
68             add(pos[l],1);
69             }
70         ask[e[i].id]=ans;
71         }
72     for(int i=1;i<=m;i++)
73         printf("%d\n",ask[i]);
74     return 0;
75     }

 

以上是关于计蒜客D2T2 蒜头君的排序(动态维护树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

复习---归并排序求逆序对--计蒜客2017noip模拟赛二--蒜头君的排序

计蒜客习题 蒜头君的猜想(埃氏筛)

计蒜客 25092 蒜头君的数轴

计蒜客 蒜头君的数轴

计蒜客模拟赛D1T2 蒜头君的树:树上节点之间最短距离和

线段树|计蒜客:斑点蛇-区间和