hdu 2492 Ping pong 线段树
给定一个序列,求出一共有多少个三元组(ai,aj,ak),使得i<j<k,ai<aj<ak。
固定中间值,查找前面比他大的有多少,比他小的有多少,查找后面比他大的有多少,比他小的有多少。
#include <stdio.h> #include <string.h> #define maxn 100200 #define N 20100 int sum[maxn*4]; int lmax[N],lmin[N],rmax[N],rmin[N]; int ans[N]; void pushup(int o) { sum[o]=sum[o*2]+sum[o*2+1]; } void build(int l,int r,int o) { if(l==r) { sum[o]=0; return ; } else { int m=(l+r)/2; build(l,m,o*2); build(m+1,r,o*2+1); pushup(o); } } void update(int p,int l,int r,int o) { if(l==r) { sum[o]++; return ; } int m=(l+r)/2; if(p<=m) update(p,l,m,o*2); else update(p,m+1,r,o*2+1); pushup(o); } int query(int L,int R,int l,int r,int o) { if(L<=l && r<=R) return sum[o]; int m=(l+r)/2,tot=0; if(L<=m) tot+=query(L,R, l,m,o*2); if(R>m) tot+=query(L,R, m+1,r,o*2+1); return tot; } int main() { int cas; scanf("%d",&cas); int n; int i,j; while(cas--) { scanf("%d",&n); __int64 xx=0; for(i=1;i<=n;i++) scanf("%d",&ans[i]); build(1,maxn,1); for(i=1;i<=n;i++) { update(ans[i],1,maxn,1); lmax[i]=query(ans[i], maxn, 1, maxn, 1)-1; lmin[i]=query(1, ans[i], 1, maxn, 1)-1; } build(1,maxn,1); for(i=n;i>0;i--) { update(ans[i],1,maxn,1); rmax[i]=query(ans[i],maxn,1,maxn,1)-1; rmin[i]=query(1,ans[i],1,maxn,1)-1; } for(i=2;i<n;i++) xx=xx+lmin[i]*rmax[i]+rmin[i]*lmax[i]; printf("%I64d\n",xx); } return 0; }