HDU-5792-World is Exploding-树状数组

来源:互联网 发布:panorama5 mac 编辑:程序博客网 时间:2024/05/10 19:42

题意:求一个n个数字的序列A[n]  其中a,b,c,d两两互不相等,1<=a<b<=n ,1<=c<d<=n  A[a]<A[b]  A[c]>A[d] 其中a,b,c,d的组数

思路:先算一个总的数量=逆序对乘顺序对。然后再减去重复,发现只有a=c a=d b=c b=d

然后用树状数组维护,首先要离散化。

ls[i],lb[i],rs[i],rb[i]分别表示左边比当前位置小的,左边比当前位置大的,右边比当前位置小的,右边比当前位置大的。

逆序对数=sigma(lb[i])

顺序对数=sigma(ls[i])

.其他的四项画了草图可得,分别为:

rs[i]*rb[i]  //a=c

lb[i]*rb[i] //a=d

ls[i]*rs[i]  //b=c

ls[i]*lb[i] //b=d

#include<bits/stdc++.h>#define maxn 55555using namespace std;int n;int c[maxn];int b[maxn];int ls[maxn],lb[maxn],rs[maxn],rb[maxn];///左边比自己小的,左边比自己大的,右边比自己小的,右边比自己大的struct NODE{    int v,num;}a[maxn];int v[maxn];bool cmp(const NODE X,const NODE Y) {    return X.v<Y.v;}int lowbit(int x) {    return x&-x;}/**单点修改区间求和**//**add(x,num);sum(r)-sum(l-1);每次x号位置修改num求lr闭区间的和**/void add(int k,int num) {    while(k<=n) {        c[k]+=num;        k+=lowbit(k);    }}int sum(int k) {    int ans=0;    while(k) {        ans+=c[k];        k-=lowbit(k);    }    return ans;}void init(void) {    memset(ls,0,sizeof ls);    memset(lb,0,sizeof lb);    memset(rs,0,sizeof rs);    memset(rb,0,sizeof rb);}int main(){    while(scanf("%d",&n)!=EOF) {        for(int i=1;i<=n;i++) {            scanf("%d",&a[i].v);            a[i].num=i;        }        sort(a+1,a+n+1,cmp);        for(int i=1;i<=n;i++) {            v[a[i].num]=i;            if(a[i].v==a[i+1].v) {                for(int j=i+1;j<=n;j++) {                    v[a[j].num]=i;                    if(a[j+1].v!=a[j].v) {                        i=j;break;                    }                }            }        }      /*  for(int i=1;i<=n;i++)            cout << v[i] << " ";        cout << endl;*/        memset(c,0,sizeof c);        for(int i=1;i<=n;i++) {            ls[i]=sum(v[i]-1);            lb[i]=i-1-sum(v[i]);            add(v[i],1);        }        memset(c,0,sizeof c);        for(int i=n;i>=1;i--) {            rs[i]=sum(v[i]-1);            rb[i]=sum(n)-sum(v[i]);            add(v[i],1);        }        long long ans=0;        long long ans1=0;        long long ans2=0;        for(int i=1;i<=n;i++) {            ans1+=ls[i];            ans2+=lb[i];        }        ans=ans1*ans2;        for(int i=1;i<=n;i++) {            ans-=rs[i]*rb[i]; //a=c            ans-=lb[i]*rb[i]; //a=d            ans-=ls[i]*rs[i]; //b=c            ans-=ls[i]*lb[i]; //b=d        }        printf("%lld\n",ans);    }    return 0;}





abcd,1a<bn,1c<dn,Aa<Ab,Aabcd,1a<bn,1c<dn,Aa<Ab,Ac>Ad.
rs[i]*rb[i]; //a=c

abcd,1a<bn,1c<dn,Aa<Ab,Ac>Ad.
0 0