BZOJ3289: Mato的文件管理

【传送门:BZOJ3289


简要题意:

  给出n个数,有m个询问,每个询问输入l,r,求出l到r中的所有数通过与相邻数交换变为上升序列的交换次数


题解:

  一开始想用在线算法做

  想不出来就用离线了

  就想到用莫队

  然后对于操作的继承,发现:

  ①在一列数的后面添加一个数,逆序对数会增加数列中比它大的数的个数。

  ②在一列数的后面删除一个数,逆序对数会减少数列中比它大的数的个数。

  ③在一列数的前面添加一个数,逆序对数会增加数列中比它小的数的个数。

  ④在一列数的前面删除一个数,逆序对数会减少数列中比它小的数的个数。

  以上抠神犇博客(因为我太懒了,发现了这些之后懒得写。。)

  设a[i]为当前l到r区间内>=i的数的个数,自然(r-l+1)-a[i]为当前l到r区间内<i的数的个数

  发现要区间修改值,原本想用线段树,后来发现树状数组差分可以做,就写了树状数组

  我的代码略丑,因为如果l<r的情况不知道怎么的就会错,所以加了几句判断

  一把辛酸泪


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
struct LS
{
    int d,id;
}s[51000];
struct qn
{
    int l,r,id;
    LL d;
}q[51000];
int bk[51000];
bool cmp(qn n1,qn n2)
{
    return bk[n1.l]==bk[n2.l]?n1.r<n2.r:bk[n1.l]<bk[n2.l];
}
bool cmpd(qn n1,qn n2)
{
    return n1.id<n2.id;
}
bool lsd(LS n1,LS n2)
{
    return n1.d<n2.d;
}
bool lsid(LS n1,LS n2)
{
    return n1.id<n2.id;
}
LL a[51000];
int lowbit(int x){return x&-x;}
int n;
LL getsum(int x)
{
    LL ans=0;
    while(x!=0)
    {
        ans+=a[x];
        x-=lowbit(x);
    }
    return ans;
}
void change(int x,LL c)
{
    while(x<=n)
    {
        a[x]+=c;
        x+=lowbit(x);
    }
}
LL t[51000];
int main()
{
    scanf("%d",&n);
    int block=int(sqrt(n));
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&s[i].d);
        s[i].id=i;
        bk[i]=(i-1)/block+1;
    }
    sort(s+1,s+n+1,lsd);
    for(int i=1;i<=n;i++) s[i].d=i;
    sort(s+1,s+n+1,lsid);
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    int l=1,r=0;
    LL ans=0;
    memset(a,0,sizeof(a));
    for(int i=1;i<=m;i++)
    {
        while(l<q[i].l)
        {
            if(l>r){l++;continue;}
            ans-=(r-l+1)-getsum(s[l].d);
            change(1,-1);
            if(s[l].d!=n) change(s[l].d+1,1);
            l++;
        }
        while(l>q[i].l)
        {
            if(l>r+1){l--;continue;}
            ans+=(r-l+1)-getsum(s[l-1].d);
            l--;
            change(1,1);
            if(s[l].d!=n) change(s[l].d+1,-1);
        }
        while(r<q[i].r)
        {
            if(l>r+1){r++;continue;}
            ans+=getsum(s[r+1].d);
            r++;
            change(1,1);
            if(s[r].d!=n) change(s[r].d+1,-1);
        }
        while(r>q[i].r)
        {
            if(l>r){r--;continue;}
            ans-=getsum(s[r].d)-1;
            change(1,-1);
            if(s[r].d!=n) change(s[r].d+1,1);
            r--;
        }
        q[i].d=ans;
    }
    sort(q+1,q+m+1,cmpd);
    for(int i=1;i<=m;i++) printf("%lld\n",q[i].d);
    return 0;
}

 

posted @ 2018-03-04 20:08  Star_Feel  阅读(173)  评论(0编辑  收藏  举报