HDU5792 World is Exploding (树状数组)

HDU5792 World is Exploding

Mean

给一个长度\(n\)的序列\(A\),问有多少四元组\((a,b,c,d)\)满足:\(4\)个数两两不同,\(1 <= a < b <= n\)\(1 <= c < d <= n\)\(A_a < A_b,A_c > A_d\)

Sol

树状数组+容斥

用树状数组记录第\(i\)位前面有多少个数比它小,前面有多少个数比它大,后面有多少个数比它小,后面有多少个比它大。

先将所有仅满足\(A_a < A_b,A_c > A_d\)的数对求出,用容斥将不合法的减掉即可.

具体看代码吧.

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
typedef long long ll;
#define lowbit(x) (x&(-x))
int q[N];
int kep[N];
ll l1[N],l2[N],r1[N],r2[N];
int n;
ll c1[N],c2[N],c3[N],c4[N];
ll get(ll c[],ll pos){
  ll ans=0;
  while(pos){
    ans=ans+c[pos];
    pos-=lowbit(pos);
  }
  return ans;
}
void add(ll c[],ll pos,ll val){
  while(pos<N){
    c[pos]+=val;
    pos+=lowbit(pos);
  }
}
int main(){
  while(scanf("%d",&n)!=EOF){
      for(int i=1;i<N;++i){
        c1[i]=c2[i]=c3[i]=c4[i]=0;
      }
      for(int i=1;i<=n;++i){
        scanf("%d",&q[i]);
        kep[i]=q[i];
      }
      sort(kep+1,kep+1+n);
      int sz = unique(kep+1,kep+1+n)-(kep+1);
      for(int i=1;i<=n;++i){
        q[i]=lower_bound(kep+1,kep+1+sz,q[i])-(kep)+1;
      }
      ll sum1=0,sum2=0;
      for(int i=1;i<=n;++i){
        l1[i]=get(c1,q[i]-1);
        add(c1,q[i],1);
        sum1+=l1[i];

        r2[i]=get(c4,N-1)-get(c4,q[i]);
        add(c4,q[i],1);
      }
      for(int i=n;i>=1;i--){
        r1[i]=get(c3,q[i]-1);
        add(c3,q[i],1);
        sum2+=r1[i];

        l2[i]=get(c2,N-1)-get(c2,q[i]);
        add(c2,q[i],1); 
      }
      ll ans=sum1*sum2;
      for(int i=1;i<=n;++i){
        ans=(ans-l1[i]*r1[i]-l2[i]*r1[i]-l1[i]*r2[i]-l2[i]*r2[i]);
      }
     
      printf("%lld\n",ans);
  }

  return 0;
}
posted @ 2021-10-18 17:14  Qquun  阅读(26)  评论(0)    收藏  举报