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 }

 

你可能感兴趣的:(ping)