POJ3928 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 }
原文地址:https://www.cnblogs.com/zhsl/p/2834732.html