【BZOJ3289】Mato的文件管理,莫队+树状数组

来源:互联网 发布:淘宝营销活动图片 编辑:程序博客网 时间:2024/05/19 00:52

Time:2016.09.07
Author:xiaoyimi
转载注明出处谢谢


传送门
思路:
这个题意就是让你求[l,r]的逆序对数
暴力做的话是O(Qn2)O(Qnlogn)
考虑莫队做法
那怎么在莫队转移的时候快速计算逆序对数呢?
如果我们当前的区间是[l,r]
转移[l+1,r]—>减去的答案就是[l,r]中比a[l]小的数的个数
转移[l-1,r]—>加上的答案就是[l,r]中比a[l-1]小的数的个数
转移[l,r+1]—>加上的答案就是[l,r]中比a[r+1]大的数的个数
转移[l,r-1]—>减去的答案就是[l,r]中比a[r]大的数的个数
这个东西我们可以用离散化+树状数组来搞啊
这样的话复杂度就是O(nnlogn)
比较玄学的复杂度
注意离散化后树状数组的区间并不是[1,n]
代码:

#include<cstdio>#include<iostream>#include<algorithm>#include<cmath> #define low(x) (x&-x)#define M 50003using namespace std;int n,m;int a[M],b[M],c[M],d[M],block[M];struct query{    int l,r,id;}q[M];bool cmp(query a,query b){    if (block[a.l]==block[b.l]) return a.r<b.r;    return block[a.l]<block[b.l];}int in(){    int t=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();    return t;}void add(int x,int val){    for (;x<=b[0];x+=low(x))        d[x]+=val; }int get(int x){    int ans=0;    for (;x;x-=low(x))        ans+=d[x];    return ans;}main(){    n=in();    int t=sqrt(n);    for (int i=1;i<=n;++i)        a[i]=b[i]=in(),        block[i]=i/t+1;    sort(b+1,b+n+1);    b[0]=unique(b+1,b+n+1)-b-1;    for (int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+b[0]+1,a[i])-b;    m=in();    for (int i=1;i<=m;++i) q[i]=(query){in(),in(),i};    sort(q+1,q+m+1,cmp);    int L=1,R=0,ans=0;    for (int i=1;i<=m;++i)    {        for (int j=R+1;j<=q[i].r;++j)            ans+=get(b[0])-get(a[j]),            add(a[j],1);        for (int j=R;j>q[i].r;--j)            ans-=get(b[0])-get(a[j]),            add(a[j],-1);        for (int j=L;j<q[i].l;++j)            ans-=get(a[j]-1),            add(a[j],-1);        for (int j=L-1;j>=q[i].l;--j)            ans+=get(a[j]-1),            add(a[j],1);        L=q[i].l;R=q[i].r;        c[q[i].id]=ans;    }    for (int i=1;i<=m;++i) printf("%d\n",c[i]);}
0 0
原创粉丝点击