UVA 1428 Ping pong
http://acm.sdibt.edu.cn:8080/judge/contest/view.action?cid=1188#problem/A
二叉检索树标准题目
题意很简单 有一些水平不同的n个乒乓球爱好者 他们之间要进行两两比赛 同时 裁判 满足住在两选手中间 且水平居于二者中间才可以进行比赛 问可进行几场比赛
最笨的方法会超时 最多有20000个乒乓球爱好者 最坏20000*20000 而时间限制为3000毫秒 (3秒)
这个题一定要 动态修改单个元素值并求前缀和————这正是BIT的标准用法
首先在 O(nlogr)(这里的 r 为 a[i] 的上限 )时间内 求出 所有sumpre[i] ,同理可计算出sumsuf[i],然后在O(n)时间内累加出最后答案
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <stdlib.h> 5 #include <cstdio> 6 7 #include <queue> 8 #include <vector> 9 #include <algorithm> 10 #include <cmath> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <string.h> 15 //freopen ("in.txt" , "r" , stdin); 16 using namespace std; 17 18 #define eps 1e-9 19 #define zero(_) (abs(_)<=eps) 20 #define max(x,y) x>y?x:y 21 const double pi=acos(-1.0); 22 23 int c[100005],sumpre[20004],sumsuf[20004],x[20004]; 24 25 26 //int a[100005];这里a表示每个节点内存的数,该题用不到,因为初始a里都为0,每次动态为某一节点增加值时只需改变c就好 27 28 int nn;//表示一共有n个数,建成BIT树后,即表示n个节点,节点序号从1--n 29 30 int lowbit(int x)//求数x的二进制表达式最右边的1所对应的值 31 { 32 return x&-x; 33 } 34 35 /*void cc()//求c[i] 36 { 37 for(i=1; i<=nn; i++) 38 { 39 int k=i-lowbit(i); 40 for(j=k+1; j<=i; j++) 41 c[i]+=a[j]; 42 } 43 }*/ 44 45 int sum_qianzui(int i)//求前缀si的和 O(logr) 46 //方法:顺着节点i,向左走,边走边往上爬,把沿途经过的ci加起来就是 47 { 48 int sum=0; 49 while(i>0) 50 { 51 sum+=c[i]; 52 i=i-lowbit(i);//求前缀的和 向左走 往上爬 53 } 54 return sum; 55 } 56 57 void modify(int i,int d)//修改c[i]的数据 O(logr) 58 //即,当在i节点所对应的数据(a[i])上增加d,改变哪些c[i] 59 //方法:从c[i],向右走,边走边往上爬,沿途修改所有节点所对应的c[i] 60 { 61 while(i<=nn) 62 { 63 c[i]+=d; 64 i=i+lowbit(i); 65 } 66 } 67 68 int main() 69 { 70 int t; 71 int i,n; 72 long long sum; 73 scanf("%d",&t); 74 while(t--) 75 { 76 //memset(a,0,sizeof(a)); 77 memset(c,0,sizeof(c)); 78 nn=0; 79 scanf("%d",&n); 80 for(i=1; i<=n; i++) 81 { 82 scanf("%d",&x[i]); 83 nn=max(nn,x[i]); 84 } 85 sum=0; 86 for(i=2; i<n; i++)//求对于第i个数,其前面比他小的数的个数 87 { 88 modify(x[i-1],1); 89 sumpre[i]=sum_qianzui(x[i]-1); 90 } 91 92 memset(c,0,sizeof(c)); 93 for(i=n-1; i>1; i--)//求对于第i个数,其后面比他小的个数 94 { 95 modify(x[i+1],1); 96 sumsuf[i]=sum_qianzui(x[i]-1); 97 } 98 99 for(i=2; i<n; i++) 100 { 101 sum+=(sumpre[i]*(n-i-sumsuf[i])+(i-1-sumpre[i])*sumsuf[i]); 102 } 103 printf("%lld\n",sum); 104 105 } 106 return 0; 107 }