LA 4329 树状数组(BIT) 维护更新一段区间的前缀和

来源:互联网 发布:知其不善则速改以从善 编辑:程序博客网 时间:2024/06/05 19:46

树状数组(BIT)的标准用法:动态地修改单个元素值,并求前缀和。

这里进行了一次转化,把一个数是否出现赋值为1或0.

这题要求某个元素前面比它小的元素个数和后面比它小的元素个数,可以用两个输转数组维护。

代码:

#include<iostream>#include<cstdio>#include<vector>#include<string>#include<queue>#include<cmath>#include<algorithm>#include<cstring>#define maxn 20005#define maxm 100005#define INF 0xfffffff#define mem(a,b) memset(a,b,sizeof(a))#define FOR(i,s,t) for(int i=s;i<=t;i++)#define ull unsigned long long#define ll long longusing namespace std;int a[maxn],c[maxm],mi[maxn],ma[maxn];//x[j]表示从做到右是否出现过j=a[k] (1<=k&&k<=i)//c[]即x数组的前缀和,mi即从1到i-1,小于a[i]的元素个数//x2[],c2[],ma[] 从右向左,基本同理。int lowbit(int x){    return x&(-x);}void add(int x,int d){    while(x<=maxm)    {        c[x]+=d;        x+=lowbit(x);    }}int sum(int x){    int ret=0;    while(x)    {        ret+=c[x];        x-=lowbit(x);    }    return ret;}void init(int n){    for(int i=1;i<=n;i++)    {        mi[i]=0,ma[i]=0;    }    memset(c,0,sizeof(c));}int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n;        scanf("%d",&n);        init(n);        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            add(a[i],1);            mi[i]=sum(a[i]-1);        }        memset(c,0,sizeof(c));        for(int i=n;i>=1;i--)        {            add(a[i],1);            ma[i]=sum(a[i]-1);        }//        output(n);        ll ret=0;        for(int i=1;i<=n;i++)        {            ret=ret+(ll)mi[i]*(n-i-ma[i])+(ll)(i-1-mi[i])*ma[i];        }        printf("%lld\n",ret);    }return 0;}


原创粉丝点击