题目大意:
对于任意一组 x,y,z 满足
x<y<z && (a[x] < a[y] < a[z] || a[x]>a[y]>a[z] )
如果有其中一个元素不同,则称为不同。
问给出的序列里有多少组不同。
思路:
用线段树维护 一个数左边有多少个数比其小
右边有多少个数比其大。
然后相乘就得当前y可以得到的数量。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 100005 #pragma comment (linker,"/STACK:102400000,102400000") using namespace std; typedef long long LL; int tre[maxn<<2]; void pushup(int num) { tre[num]=tre[num<<1]+tre[num<<1|1]; } int query(int num,int s,int e,int l,int r) { if(l<=s && r>=e) { return tre[num]; } int mid=(s+e)>>1; if(r<=mid)return query(lson,l,r); else if(l>mid)return query(rson,l,r); else { return query(lson,l,mid)+query(rson,mid+1,r); } } void update(int num,int s,int e,int pos) { if(s==e) { tre[num]++; return; } int mid=(s+e)>>1; if(pos<=mid)update(lson,pos); else update(rson,pos); pushup(num); } int save[20005]; int lit[20005]; int big[20005]; int main() { int T; int n; scanf("%d",&T); while(T--) { scanf("%d",&n); memset(tre,0,sizeof tre); int Max=-1; for(int i=1;i<=n;i++) { scanf("%d",&save[i]); Max=max(save[i],Max); } for(int i=1;i<=n;i++) { lit[i]=query(1,1,Max,1,save[i]); update(1,1,Max,save[i]); } memset(tre,0,sizeof tre); for(int i=n;i>=1;i--) { big[i]=query(1,1,Max,save[i],Max); update(1,1,Max,save[i]); } LL ans=0; for(int i=1;i<=n;i++) { ans+=lit[i]*big[i]; ans+=(i-1-lit[i])*(n-i-big[i]); } printf("%I64d\n",ans); } return 0; }
hdu 2492 Ping pong (线段树),布布扣,bubuko.com
原文:http://blog.csdn.net/u010709592/article/details/24204931