【BZOJ 3295】动态逆序对 - 分块+树状数组

来源:互联网 发布:vasp5.2软件下载 编辑:程序博客网 时间:2024/05/21 06:56

题目描述

给定一个1~n的序列,然后m次删除元素,每次删除之前询问逆序对的个数。

分析:分块+树状数组

(PS:本题的CDQ分治解法见下一篇)

首先将序列分成T块,每一块开一个树状数组,并且先把最初的答案统计完成。

对于每一次删除,找到对应位置,考虑删除之后的增减情况:
①块内:直接暴力,对于左边,少了比它大的个数,对于右边,少了比它小的个数,O(nT)
②块外:枚举每一块。对于左边,少了比它大的个数,对于右边,少了比它小的个数,O(Tlogn)
然后把这个位置的数分别从数组和树状数组中删除,O(logn)

为了最小化时间,我们使nT=Tlogn,忽略log,所以取T=n即可。

小结

一些自己不容易出错的写法:
①本题数组使用*a的方法
②涉及lint,须检验 参数声明、变量声明、函数声明、输入输出
③同一行最多只能有一类函数,且不要与其他运算,否则使用tmp
④分块的问题,直接将块的大小设为确定值,并标记块的个数上限,还有就是(i-1)/unit+1的写法
⑤对于一个参数,如果需要作空间且需要枚举,若数值上的差>1,那么开两个参数
⑥对于一个整数a判断是否大于0,写作a>0,不要写作a

代码

#include <cstdio>#include <cctype>#include <cmath>#include <algorithm>using namespace std;typedef long long lint;const int N=100010;const int BLOCK_SIZE=1000;const int BLOCK_NUM=101;int n,m;int a[N];int loc[N];lint t[N];lint res;int num;lint tr[BLOCK_NUM][N];inline int read(void){    int x=0; char c=getchar();    for (;!isdigit(c);c=getchar());    for (;isdigit(c);c=getchar()) x=x*10+c-'0';    return x;}inline int lowbit(int i){    return i&-i;}inline void ins(lint *ta,int i,int add){    for (;i<=n;i+=lowbit(i)) ta[i]+=add;}inline lint query(lint *ta,int i){    lint sum=0;    for (;i;i-=lowbit(i)) sum+=ta[i];    return sum;}inline void update(int x){    int loca=loc[x],bel=(loca-1)/BLOCK_SIZE+1;    for (int i=BLOCK_SIZE*(bel-1)+1;i<loca;i++)        if (a[i]>0&&a[i]>x) res--;    for (int i=loca+1;i<=min(BLOCK_SIZE*bel,n);i++)        if (a[i]>0&&a[i]<x) res--;    lint tmp;    for (int i=1;i<bel;i++)    {        tmp=query(tr[i],n)-query(tr[i],x-1);        res-=tmp;    }    for (int i=bel+1;i<=num;i++)    {        tmp=query(tr[i],x-1);        res-=tmp;    }    a[loca]=0;    ins(tr[bel],x,-1);}int main(void){//  freopen("a.in","r",stdin);//  freopen("a.out","w",stdout);    n=read(),m=read();    for (int i=1;i<=n;i++) a[i]=read();    for (int i=1;i<=n;i++) loc[a[i]]=i;    lint tmp;    for (int i=n;i>=1;i--)    {        tmp=query(t,a[i]);        res=res+tmp;        ins(t,a[i],1);    }    int belo;    num=(n-1)/BLOCK_SIZE+1;    for (int i=1;i<=n;i++)    {        belo=(i-1)/BLOCK_SIZE+1;        ins(tr[belo],a[i],1);    }    for (int i=1;i<=m;i++)    {        printf("%lld\n",res);        update(read());    }    return 0;}
0 0