ZROI2018提高day6t1

传送门

分析

我们发现这个四元组可以分解成一个逆序对拼上一个顺序对,这个线段树搞搞然后乘一下就可以求出来了,但是我们发现可能有(a,b)为逆序对且(b,c)为顺序对的情况,所以要进行容斥,我们只需要枚举是哪一个点重合然后减掉即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
long long a[100100],b[100100],d[440000],sum,d1[440000];
long long S1[100100],S2[100100],S11[100100],S21[100100];
map<long long,long long>id;
inline void add(long long le,long long ri,long long wh,long long pl,long long k){
    d[wh]+=k;
    if(le==ri)return;
    long long mid=(le+ri)>>1;
    if(mid>=pl)add(le,mid,wh<<1,pl,k);
      else add(mid+1,ri,wh<<1|1,pl,k);
    return;
}
inline void add2(long long le,long long ri,long long wh,long long pl,long long k){
    d1[wh]+=k;
    if(le==ri)return;
    long long mid=(le+ri)>>1;
    if(mid>=pl)add2(le,mid,wh<<1,pl,k);
      else add2(mid+1,ri,wh<<1|1,pl,k);
    return;
}
inline long long q(long long le,long long ri,long long x,long long y,long long wh){
    if(x>y)return 0;
    if(le>=x&&ri<=y)return d[wh];
    long long mid=(le+ri)>>1,ans=0;
    if(mid>=x)ans+=q(le,mid,x,y,wh<<1);
    if(mid<y)ans+=q(mid+1,ri,x,y,wh<<1|1);
    return ans;
}
inline long long q2(long long le,long long ri,long long x,long long y,long long wh){
    if(x>y)return 0;
    if(le>=x&&ri<=y)return d1[wh];
    long long mid=(le+ri)>>1,ans=0;
    if(mid>=x)ans+=q2(le,mid,x,y,wh<<1);
    if(mid<y)ans+=q2(mid+1,ri,x,y,wh<<1|1);
    return ans;
}
int main(){
    long long n,m,i,j,k,sum1=0,sum2=0;
    scanf("%lld",&n);
    id.clear();
    for(i=1;i<=n;i++)scanf("%lld",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    for(i=1;i<=n;i++)
      if(!id[b[i]])
        id[b[i]]=++sum;
    for(i=1;i<=n;i++){
      long long x=q(1,sum,1,id[a[i]]-1,1),y=q(1,sum,id[a[i]]+1,sum,1);
      sum1+=x;sum2+=y;
      add(1,sum,1,id[a[i]],1);
    }
    long long Ans=(long long)sum1*sum2;
    memset(d,0,sizeof(d));
    memset(d1,0,sizeof(d1));
    for(i=1;i<=n;i++){
      S1[i]=q(1,sum,1,id[a[i]]-1,1);
      S11[i]=q(1,sum,id[a[i]]+1,sum,1);
      add(1,sum,1,id[a[i]],1);
    }
    for(i=n;i>0;i--){
      S2[i]=q2(1,sum,1,id[a[i]]-1,1);
      S21[i]=q2(1,sum,id[a[i]]+1,sum,1);
      add2(1,sum,1,id[a[i]],1);
    }
    for(i=1;i<=n;i++)
      Ans-=(long long)S1[i]*S2[i]+(long long)S11[i]*S1[i]+(long long)S21[i]*S2[i]+(long long)S21[i]*S11[i];
    printf("%lld\n",Ans);
    return 0;
}
posted @ 2018-10-16 14:48  水题收割者  阅读(165)  评论(0编辑  收藏  举报