在一个小镇上住着n位武林高手,他们互相之间经常PK,不过PK的时候必须要有一位裁判在场。这个小镇上的房子从1—n依次排列(一条直线上),两个人要单挑时必须到另一个人的家里,让这个人作为裁判,裁判的武功不能同时比两个人低也不能同时比两个人高。由于每个高手都很懒,所以他们走的路程不能比他俩之间的距离远(即只能在他们序号之间高手中选择裁判)。求小镇上最多能进行几场PK。
很久以前就看到过这个题,当时肯定是不会。现在听说是树状数组做,因为不怎么会,就又把树状数组看了一遍。。
树状数组貌似都要离散化,先排个序什么的。这道题先用结构体记下每个人的武功值和序号,再按武功值排序(武功相等的序号小的在前)。然后按这个顺序先顺着循环一遍,循环过程中对每个序号(a[i].order)调用sum函数,也就是插入这个序号前有多少个序号比它小(正是武功值也比它小,序号也比它小),用lmin[i]记录在i左边武功比i小的,(是排了序后的第i个人),那么在i左边武功比i大的人数就是i-lmin[i](i从0开始),用lmax[i]记下,再插入a[i].order。接着重新倒着循环一遍,同理可求出rmin[]和rmax[],最后答案就是lmin[i]*rmax[i]+lmax[i]*rmin[i]
的和。注意树状数组的起点是1。
#include<cstring> #include<cstdio> #include<iostream> #include<climits> #include<cmath> #include<algorithm> #include<queue> #include<map> #define INF 0x3f3f3f3f using namespace std; int T,N; long long lmin[400010],lmax[400010],rmin[400010],rmax[400010],c[400010]; struct node{ int value,order; }a[100010]; bool cmp(node a,node b){ if(a.value==b.value) return a.order<b.order; return a.value<b.value; } int lowbit(int x){ return x&(-x); } void add(int i,int v){ while(i<=N){ c[i]+=v; i+=lowbit(i); } } int sum(int i){ int s=0; while(i>0){ s+=c[i]; i-=lowbit(i); } return s; } int main(){ // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--){ scanf("%d",&N); int i; long long ans=0; for(i=0;i<N;i++){ scanf("%d",&a[i].value); a[i].order=i+1; } sort(a,a+N,cmp); memset(c,0,sizeof(c)); for(i=0;i<N;i++){ int s=sum(a[i].order); lmin[i]=s; lmax[i]=i-s; add(a[i].order,1); } memset(c,0,sizeof(c)); for(i=N-1;i>=0;i--){ int s=sum(a[i].order); rmin[i]=s; rmax[i]=N-i-1-s; add(a[i].order,1); } for(i=0;i<N;i++) ans+=(lmin[i]*rmax[i]+lmax[i]*rmin[i]); printf("%lld\n",ans); } return 0; }
#include<cstring> #include<cstdio> #include<iostream> #include<climits> #include<cmath> #include<algorithm> #include<queue> #include<map> #define INF 0x3f3f3f3f using namespace std; int T,N; long long lmin[400010],lmax[400010],rmin[400010],rmax[400010],c[400010]; struct node{ int value,order; }a[100010]; bool cmp(node a,node b){ if(a.value==b.value) return a.order<b.order; return a.value<b.value; } void add(int l,int r,int pos,int p,int v){ if(l==r){ c[pos]=v; return; } c[pos]+=v; int mid=(l+r)/2; if(p<=mid) add(l,mid,pos<<1,p,v); else add(mid+1,r,(pos<<1)+1,p,v); } int sum(int l,int r,int pos,int p){ if(l==r) return c[pos]; int mid=(l+r)/2; if(p<=mid) return sum(l,mid,pos<<1,p); else return c[pos<<1]+sum(mid+1,r,(pos<<1)+1,p); } int main(){ // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--){ scanf("%d",&N); int i; long long ans=0; for(i=0;i<N;i++){ scanf("%d",&a[i].value); a[i].order=i+1; } sort(a,a+N,cmp); memset(c,0,sizeof(c)); for(i=0;i<N;i++){ int s=sum(1,N,1,a[i].order); lmin[i]=s; lmax[i]=i-s; add(1,N,1,a[i].order,1); } memset(c,0,sizeof(c)); for(i=N-1;i>=0;i--){ int s=sum(1,N,1,a[i].order); rmin[i]=s; rmax[i]=N-i-1-s; add(1,N,1,a[i].order,1); } for(i=0;i<N;i++) ans+=lmin[i]*rmax[i]+lmax[i]*rmin[i]; printf("%lld\n",ans); } return 0; }
要注意的是数组要开4*N。