蒜头君的排序

蒜头君的排序

题目大意

蒜头君是一个爱思考的好孩子,这一天他学习了冒泡排序,于是他就想,把一个乱序排列通过冒泡排序排至升序需要多少次交换,这当然难不倒他,于是他想来点刺激的,给定一个 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<r\sum | l[i]-l[i-1] |\ +l[i]l[i1] \sum | r[i]-r[i-1] | \ler[i]r[i1]≤ 7 \times 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

题解:

这道题要用莫队算法,首先将左端点分块,对于每一块都按右端点从小到大排序。然后维护一个树状数组维护当前区间内比i小的数的个数,特别注意一下临界条件。每次维护一下答案即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long lol;
lol n,m,a[30001],lim,c[30001],cnt[30001];
struct node
{
    lol l,r,id;
}s[30001];
lol gi()
{
    lol ans=0,f=1;
    char i=getchar();
    while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
    while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
    return ans*f;
}
bool cmp(const node a,const node b)
{
    if(a.l/lim!=b.l/lim)return a.l/lim<b.l/lim; else return a.r<b.r;
}
lol lowbit(lol x)
{
    return x&(-x);
}
void add(lol x,lol v)
{
    for(lol i=x;i<=n;i+=lowbit(i))
    c[i]+=v;
}
lol getsum(lol x)
{
    lol ans=0;
    for(lol i=x;i;i-=lowbit(i))
    ans+=c[i];
    return ans;
}
int main()
{
    lol i,j;
    n=gi();
    lim=sqrt(n);
    for(i=1;i<=n;i++)
    a[i]=gi();
    m=gi();
    for(i=1;i<=m;i++)
    {
        s[i].l=gi();
        s[i].r=gi();
        s[i].id=i;
    }
    sort(s+1,s+m+1,cmp);
    lol left=1,right=0,ans=0;
    for(i=1;i<=m;i++)
    {
        while(left<s[i].l){add(a[left],-1);ans-=getsum(a[left]-1);left++;}
        while(left>s[i].l){left--;ans+=getsum(a[left]-1);add(a[left],1);}
        while(right>s[i].r){ans-=getsum(n)-getsum(a[right]);add(a[right],-1);right--;}//
        while(right<s[i].r){right++;add(a[right],1);ans+=getsum(n)-getsum(a[right]);}//
        cnt[s[i].id]=ans;
    }
    for(i=1;i<=m;i++)
    {
        printf("%lld\n",cnt[i]);
    }
    return 0;
}

 

posted @ 2017-07-30 18:12  kakakakakaka  阅读(436)  评论(0编辑  收藏  举报

Never forget why you start

//鼠标爆炸特效