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;
}