BZOJ3289【莫队算法+树状数组+离散化】

思路:
区间逆序数即是交换次数。
逆序数,可以用树状数组吧。
怎么处理区间变换的时候求逆序数啊。。
这里分成左边的增/删,右边的增/删
因为是按时序插入,
所以左边增,增一个数,计算:ans+=sun(cur_val-1)[比他小的数的个数]
那么删:删一个数,计算ans+=sun(cur_val-1)[比他小的数的个数]
右边增的话,赠一个数,是ans+=比该值大的数的个数,那也就是ans+=区间-比他小的个数
删除同理。
补:
突然意识到莫队的每次增加区间点都意味着这个点之前所造成的贡献/效果要先删除,
然后更新这个点,
计算这个点更新后造成的贡献/效果。
而这里的话,一个点给出的效果已经知道。

WA在了树状数组算数组元素v[i]前缀和,应该是sum(v[i]-1);

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;

const int N=5e4+10;
int c[N*4],n,q;
int pos[N],v[N];
vector<int>xs;
struct asd
{
    int left,right,res,id;
} e[N];
bool cmp(asd x,asd y)
{
    if(pos[x.left]==pos[y.left]) return x.right<y.right;
    return x.left<y.left;
}
bool cmp_id(asd x,asd y)
{
    return x.id<y.id;
}

int lowbit(int x)
{
    return x&(-x);
}
void add(int x,int val)
{
    while(x<N)
    {
        c[x]+=val;
        x+=lowbit(x);
    }
}

int sum(int i)
{
    int ans=0;
    while(i)
    {
        ans+=c[i];
        i-=lowbit(i);
    }
    return ans;
}

int ans;
int solve()
{
    memset(c,0,sizeof(c));
    ans=0;
    for(int i=0,L=1,R=0; i<q; i++)
    {
        while(R<e[i].right)//右增;
        {
            add(v[R+1],1);
            ans+=R+1-L+1-sum(v[R+1]);//区间-比他小的数-他本身的数。
            R++;
        }
        while(R>e[i].right)//右缩
        {
            ans-=R-L+1-sum(v[R]);//区间-比他小的数-他本身的数。
            add(v[R],-1);
            R--;
        }
        while(L<e[i].left)//左缩
        {
            ans-=sum(v[L]-1);
            add(v[L],-1);
            L++;
        }
        while(L>e[i].left)//左扩
        {
            add(v[L-1],1);
            ans+=sum(v[L-1]-1);
            L--;
        }
        e[e[i].id].res=ans;
    }
}

int main()
{
    scanf("%d",&n);
    int block=(int)sqrt(n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&v[i]);
        xs.push_back(v[i]);
        pos[i]=(i-1)/block+1;
    }
    sort(xs.begin(),xs.end());
    for(int i=1;i<=n;i++)
        v[i]=lower_bound(xs.begin(),xs.end(),v[i])-xs.begin()+1;
    scanf("%d",&q);
    for(int i=0; i<q; i++)
    {
        scanf("%d%d",&e[i].left,&e[i].right);
        e[i].id=i;
    }
    sort(e,e+q,cmp);
    solve();
    for(int i=0; i<q; i++)
        printf("%d\n",e[i].res);
    return 0;
}
/*
4
1 4 2 3
2
1 2
2 4
5
9 8 5 3 2
1

*/





posted @ 2017-02-18 00:20  see_you_later  阅读(131)  评论(0编辑  收藏  举报