POJ-3928 Ping pong 线段树 | 树状数组
题目链接:http://poj.org/problem?id=3928
题目大意是:有n个人按顺序住在一条街上,给定每个人的乒乓球的技术水平值。现在他们要切磋球技,两两切磋,需要找一名裁判,这名裁判的球技水平必须在他们之间,而且他必须居住在他们之间。问一共有多少种情况。
如果直接枚举任意两个数,复杂度O(n^2),此题数据达到20000,铁定TLE。我们可以反过来枚举裁判,那么只要O(n)。接下来就是在[0,i-1]比num[i]小的数的个数,这里是关键,直接遍历的话也会TLE。这里并没有要求动态访问,只要求出结果即可,因此可以离线操作,用线段树优化。具体做法就是,从0开始遍历数列,依次更新num[i]到线段树中,线段树中的作用是统计区间已更新的数的个数,因此当读取到num[i]的时候我们就可以在log(n)的时间内求出比num[i]小的数的个数。求比num[i]大的数情况类似,接下来就是两两相乘了,但要注意还要反过来求一次,总的复杂度O(n*log(n))。区间统计用树状数组做更方便。
线段树版:
1 //STATUS:C++_AC_625MS_1964KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 #include<map> 13 using namespace std; 14 #define LL __int64 15 #define pii pair<int,int> 16 #define Max(a,b) ((a)>(b)?(a):(b)) 17 #define Min(a,b) ((a)<(b)?(a):(b)) 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 #define lson l,mid,rt<<1 20 #define rson mid+1,r,rt<<1|1 21 const int MAX=20010,INF=0x3f3f3f3f,MOD=1999997; 22 const LL LLNF=0x3f3f3f3f3f3f3f3fLL; 23 24 int num[MAX],coul[MAX],cour[MAX],sum[100010<<2]; 25 int T,n,a,b,mau,s; 26 27 void update(int l,int r,int rt,int c) 28 { 29 if(l==r){ 30 sum[rt]++; 31 return; 32 } 33 int mid=(l+r)>>1; 34 if(c<=mid)update(lson,c); 35 else update(rson,c); 36 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 37 } 38 39 void query(int l,int r,int rt) 40 { 41 if(l>=a && r<=b){ 42 s+=sum[rt]; 43 return; 44 } 45 int mid=(l+r)>>1; 46 if(a<=mid)query(lson); 47 if(b>mid)query(rson); 48 } 49 50 int main() 51 { 52 // freopen("in.txt","r",stdin); 53 int i,j; 54 LL ans; 55 scanf("%d",&T); 56 while(T--) 57 { 58 ans=0; 59 mau=-INF; 60 scanf("%d",&n); 61 for(i=0;i<n;i++){ 62 scanf("%d",num+i); 63 if(num[i]>mau)mau=num[i]; 64 } 65 66 mem(sum,0); 67 for(i=0,a=1;i<n;i++){ 68 b=num[i]; 69 s=0; 70 query(1,mau,1); 71 coul[i]=s; 72 update(1,mau,1,b); 73 } 74 mem(sum,0); 75 for(i=n-1,b=mau;i>=0;i--){ 76 a=num[i]; 77 s=0; 78 query(1,mau,1); 79 cour[i]=s; 80 update(1,mau,1,a); 81 } 82 for(i=1;i<n;i++) 83 ans+=coul[i]*cour[i]+(i-coul[i])*(n-i-cour[i]-1); 84 85 printf("%I64d\n",ans); 86 } 87 return 0; 88 }