【题目描述】
一个简单的数列问题:
给定一个长度为n的数列,求这样的三个元素 ai,aj,ak 的个数,
满足 ai<aj>ak ,且 i<j<k 。
<j<k。< span="" style="font-family: serif; font-size: 16px; line-height: 20px;">【输入格式】
第1行是一个整数n(1<=n<=50000)。
接下来n行,每行一个元素ai(0<=ai<=32767)。
【输出格式】
一个数,满足 ai<aj>ak (i<j<k) 的个数。
<j<k)的个数。< span="" style="font-family: serif; font-size: 16px; line-height: 20px;">【输入样例】
5 1 2 3 4 1
【输出样例】
6
【数据规模】
对于30%的输入数据有n<=200。
对于80%的输入数据有n<=10000。
对于100%的输入数据有n<=50000。
题解:
因为a只有32767,所以我们可以把a的值当做下标。等于把下标为a的点染上颜色。。。线段树中的值保存染上颜色的点的个数
这样我们查询区间和即可。。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long tree[200000]={0},minl[50001]={0},minr[50001]={0},a[50001]={0};
void insert(int i,int l,int r,int aa)
{
int mid;
if (l==r&&r==aa)
{
++tree[i];
return;
}
mid=(l+r)/2;
if (aa<=mid) insert(i*2,l,mid,aa);
else insert(i*2+1,mid+1,r,aa);
tree[i]=tree[i*2]+tree[i*2+1];
}
long long work(int i,int l,int r,int aa,int b)
{
long long ans=0;
int mid;
if (aa<=l&&r<=b)
return tree[i];
mid=(l+r)/2;
if (aa<=mid) ans+=work(i*2,l,mid,aa,b);
if (b>mid) ans+=work(i*2+1,mid+1,r,aa,b);
return ans;
}
int main()
{
freopen("queueb.in","r",stdin);
freopen("queueb.out","w",stdout);
int n,i,j;
long long ans=0;
scanf("%d",&n);
for (i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
a[i]+=2;
}
for (i=1;i<=n;++i)
{
insert(1,1,32769,a[i]);
if (i>1)
minl[i]=work(1,1,32769,1,a[i]-1);
}
memset(tree,0,sizeof(tree));
for (i=n;i>=1;--i)
{
insert(1,1,32769,a[i]);
if (i<n)
minr[i]=work(1,1,32769,1,a[i]-1);
if (i>1)
ans+=minl[i]*minr[i];
}
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
}