• HDU 1556 Color the ball 树状数组 题解


    Problem Description
    N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a開始到气球b依次给每一个气球涂一次颜色。

    可是N次以后lele已经忘记了第I个气球已经涂过几次颜色了。你能帮他算出每一个气球被涂过几次颜色吗?

     

    Input
    每一个測试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包含2个整数a b(1 <= a <= b <= N)。
    当N = 0。输入结束。

     

    Output
    每一个測试实例输出一行,包含N个整数。第I个数代表第I个气球总共被涂色的次数。
     

    Sample Input
    3 1 1 2 2 3 3 3 1 1 1 2 1 3 0
     

    Sample Output
    1 1 1 3 2 1

    这是一条逆向向下更新才比較方便处理数据的题目。

    每一个根节点并不是记录和。而是记录改下标下面的节点更新了一次。

    所以更新的时候须要注意,小于区间的节点要-1操作。

    就这点技巧。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    int tree[100005];
    
    inline int lowbit(int x)
    {
    	return x & (-x);
    }
    
    void update(int x, int val, int len)
    {
    	while (x > 0)
    	{
    		tree[x] += val;
    		x -= lowbit(x);//最高点记录了一个区间内涂了多少次
    	}
    }
    
    int query(int x, int len)
    {
    	int ans = 0;
    	while (x <= len)
    	{
    		ans += tree[x];
    		x += lowbit(x);//全部根节点相加才等于答案
    	}
    	return ans;
    }
    
    int main()
    {
    	int n, a, b;
    	while (scanf("%d", &n) && n != 0)
    	{
    		fill(tree, tree+n+1, 0);
    		for(int i = 0; i < n; i++)  
    		{  
    			scanf("%d%d",&a,&b);  
    			update(b,1, n);  
    			update(a-1,-1, n);  
    
    		}  
    		for(int i=1;i<n;i++)  
    		{  
    			printf("%d ",query(i, n));  
    		}  
    		printf("%d
    ",query(n, n));  
    	}
    	return 0;
    }


    事实上也能够正向填表,和一般的查询和操作几乎相同,只是注意怎样更新节点。

    的确困难,非常考脑力的。要非常用力地想,呵呵。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int SIZE = 100005;
    int tree[SIZE];
    
    inline int lowbit(int x)
    {
    	return x & (-x);
    }
    
    void update(int x, int val, int len)
    {
    	while (x <= len)
    	{
    		tree[x] += val;
    		x += lowbit(x);
    	}
    }
    
    int query(int x)
    {
    	int ans = 0;
    	while (x > 0)
    	{
    		ans += tree[x];
    		x -= lowbit(x);
    	}
    	return ans;
    }
    
    int main()
    {
    	int n, a, b;
    	while (scanf("%d", &n) && n != 0)
    	{
    		fill(tree, tree+n+1, 0);
    		for(int i = 0; i < n; i++)  
    		{  
    			scanf("%d%d",&a,&b);  
    			update(a,1, n);  
    			update(b+1,-1, n);  
    
    		}  
    		for(int i=1;i<n;i++)  
    		{  
    			printf("%d ",query(i));  
    		}  
    		printf("%d
    ",query(n));  
    	}
    	return 0;
    }


    还有以下这位朋友的博客的直接使用数组解决这个问题,使得时间效率达到O(n)了,非常巧妙,高手!

    http://blog.csdn.net/u011560507/article/details/9673529


    仿他的写了个,呵呵。

    #include <algorithm>
    #include<cstdio>    
    using namespace  std; 
    const int SIZE = 100002; 
    int arr[SIZE];    
    int main()    
    {    
    	int N;    
    	while(scanf("%d",&N) && N)
    	{    
    		fill(arr, arr+N+1, 0);
    
    		for(int i = 1; i <= N; i++)
    		{    
    			int a, b;    
    			scanf("%d %d",&a, &b);    
    			arr[a]++;    
    			arr[b+1]--;    
    		}    
    		for(int i = 1; i < N; i++)
    		{    
    			arr[i] += arr[i-1];    
    			printf("%d ", arr[i]);    
    		}
    		printf("%d
    ", arr[N] + arr[N-1]);
    	}    
    	return 0;    
    } 



  • 相关阅读:
    【转】工作流持久化的几点说明
    转:壹百度-百度十年千倍的29条法则
    CRM软件设计评测点与采集测评点
    键盘上各按键对应的ASSII值
    导入Excle数据至数据库 “外部表不是预期的格式”错误信息
    浅谈代码的执行效率(2):编译器的威力 [摘自赵劼老师的博客]
    代码的执行效率(3)缓存与局部性 摘自赵劼老师的博客
    浅谈代码的执行效率(一)
    C# Base64加解密图片
    Bulk Insert的用法
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/6733862.html
Copyright © 2020-2023  润新知