zoukankan      html  css  js  c++  java
  • LA 4329 树状数组入门

    本题是一道树状数组的入门题。直接统计比赛场数并不好办,我们采用枚举裁判的方法。考虑从左到右i个人当裁判的情形,需要统计的是前i-1个人和后n-i个人中能把第i个人的技能值“夹”在中间的情况数。注意可能是前大后小,也可能是前小后大。由于这些选手的技能值各不相同,所以我们在从左到右扫描的过程中,可维护布尔型数组f[max_Ai]表示第i个人之前技能值的“占用情况”,c[i]表示前面的人中技能值小于a[i]的人的数目,即当f[j]=true(1<=j<a[i])时,c[i]+1。同理可设d[i]表示后n-i个人中技能值小于a[i]的人的数目。但直接统计求区间和,时间无法承受。因此,f数组可用树状数组实现。最终答案即为


    写代码时,先搞清楚各个数组的意义,哪个是树状数组,哪些是普通数组;最终答案ans要用long long类型来保存;另外ACM类的题一定要注意每组数据之前都要进行初始化。


    // LA 4329 Ping Pong
    
    #include <cstdio> 
    #include <cstring>
    
     //a数组储存各选手的能力值;
     //f数组是树状数组的查询数组,f[i]=true表示当前能力值i已被打上标记 
     //c,f数组查询数组f的区间和 
     
     typedef long long LL;
     
     const int N=20000+5, AI=100000+5;
     
     int T, n, f[AI], c[N], d[N], a[N]; 
     LL ans; 
     
     int lowbit(int x) 
     {
     	return x&-x;
     }
     
     void add(int x) 
     {
     	while (x<=AI) { 
     		f[x]++; x+=lowbit(x); 
    	}
     }
     
     int sum(int x)
     {
     	int ret=0;
     	while (x>0) {
     		ret+=f[x]; x-=lowbit(x);
    	}
    	return ret;
     } 
    
     void Solve()
     {
     	scanf("%d", &n);
     	for (int i=1; i<=n; i++) scanf("%d", &a[i]);
     	memset(f, 0, sizeof(f));
     	memset(c, 0, sizeof(c));
    	for (int i=2; i<=n; i++) {
    		add(a[i-1]);
    		c[i]=sum(a[i]-1); 
    	}
    	memset(f, 0, sizeof(f));
    	memset(d, 0, sizeof(d));
    	for (int i=n-1; i>=1; i--) {
    		add(a[i+1]);
    		d[i]=sum(a[i]-1);
    	}
    	ans=0;
    	for (int i=2; i<=n-1; i++) ans+=(LL)(c[i]*(n-i-d[i])+(LL)d[i]*(i-c[i]-1));
    	printf("%llu
    ", ans);
     } 
    
    int main()
    {
    	scanf("%d", &T);
    	for (int i=1; i<=T; i++) Solve();
    
    	return 0;
    }


  • 相关阅读:
    第七周进度总结
    第六周进度总结
    第五周进度总结
    《大道至简》读后感
    第四周进度总结
    第三周进度总结
    第二周进度总结
    第一周进度总结
    top工具
    系统监控的一些工具w , vmstat
  • 原文地址:https://www.cnblogs.com/yearwhk/p/5119883.html
Copyright © 2011-2022 走看看