HDU 5792 World is Exploding(树状数组+离散化)

时间:2023-03-10 06:12:14
HDU 5792 World is Exploding(树状数组+离散化)

http://acm.split.hdu.edu.cn/showproblem.php?pid=5792

题意:
HDU 5792 World is Exploding(树状数组+离散化)

思路:

lmin[i]:表示左边比第i个数小的个数。

lmax[i]:表示左边比第i个数大的个数。

rmin[i]:表示右边比第i个数小的个数。

rmax[i]:表示右边比第i个数大的个数。

这些都是可以用树状数组计算出来的,把所有的lmin加起来就是所有(a,b)对的个数,所有lmax加起来就是所有(c,d)对的个数,两者相乘就是所有情况之和了。但是需要注意的是,在这些情况中还存在a=c,a=d,b=c,b=d这四种不符合题意的,需要把这些给减掉。

 #include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn = +; int n;
int a[maxn],b[maxn],c[maxn];
int lmin[maxn],lmax[maxn],rmin[maxn],rmax[maxn]; int lowbit(int x)
{
return x&-x;
} int get_sum(int x)
{
int ret = ;
while(x>)
{
ret+=c[x];
x-=lowbit(x);
}
return ret;
} void add(int x)
{
while(x<=n)
{
c[x]+=;
x+=lowbit(x);
}
} int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+,b+n+);
int num=unique(b+,b+n+)-(b+);
for(int i=;i<=n;i++)
a[i]=lower_bound(b+,b+num+,a[i])-(b+)+; ll suml=,sumr=;
memset(c,,sizeof(c));
for(int i=;i<=n;i++)
{
lmin[i]=get_sum(a[i]-);
lmax[i]=get_sum(n)-get_sum(a[i]);
add(a[i]);
suml+=lmin[i];
sumr+=lmax[i];
}
memset(c,,sizeof(c));
for(int i=n;i>=;i--)
{
rmin[i]=get_sum(a[i]-);
rmax[i]=get_sum(n)-get_sum(a[i]);
add(a[i]);
} ll ans=suml*sumr; for(int i=;i<=n;i++)
{
ans-=(ll)rmin[i]*rmax[i];//a==c==a[i]
ans-=(ll)lmin[i]*lmax[i];//b==d==a[i]
ans-=(ll)lmin[i]*rmin[i];//b==c==a[i]
ans-=(ll)lmax[i]*rmax[i];//a==d==a[i]
}
printf("%lld\n",ans);
}
return ;
}