HDU - 1556 Color the ball(树状数组)
N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
每个测试实例第一行为一个整数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 0Sample Output
1 1 1 3 2 1
解题思路:本题可以想到三种方法,暴力, 线段树, 树状数组。暴力的话复杂度为O(n^2),显然会超时。由于我现在还不会线段树,所以就只能树状数组了吧233
这道题树状数组有些不同,以前都是对点更新找区间,这个是对区间更新找点,那么具体怎么做呢,首先要理解树状数组的c[]数组每个元素代表的是一段区间的值,我们把区间抽象成点,Sum(i)可以表示第i个气球被涂色的次数(画张图就可以理解),比如我们要涂色x~y区间的气球,那么我们先对x进行+1更新操作,相当于[x,MaxN]的气球被涂色一次,但由于我们只涂了x~y区间的气球,y+1及其以后的气球应该都没有涂色,那么我们把y+1再进行一次-1的更新操作就可以了,相当于[y+1,MaxN]的气球这次没有被涂色。这样进行操作始终保证了Sum(i)是第i个气球被涂色的次数。
代码:
1 #include<cstdlib> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<string> 6 #include<iostream> 7 #include<algorithm> 8 #include<map> 9 #include<vector> 10 using namespace std; 11 const int MaxN = 1e5; 12 13 int n; 14 int num[MaxN+5], c[MaxN+5]; 15 16 int lowbit(int x) 17 { 18 return x&(-x); 19 } 20 21 void Add(int x, int y) 22 { 23 for(int i = x;i <= n;i += lowbit(i)) 24 { 25 c[i] += y; 26 } 27 } 28 29 int Sum(int x) 30 { 31 int ans = 0; 32 for(int i = x;i > 0;i -= lowbit(i)) 33 { 34 ans += c[i]; 35 } 36 return ans; 37 } 38 39 40 int main() 41 { 42 int a, b; 43 while(cin >> n && n) 44 { 45 memset(num, 0, sizeof(num)); 46 memset(c, 0, sizeof(c)); 47 for(int i = 1;i <= n;i++) 48 { 49 cin >> a >> b; 50 Add(a, 1); 51 Add(b + 1, -1); 52 } 53 printf("%d", Sum(1)); 54 for(int i = 2;i <= n;i++) 55 { 56 printf(" %d", Sum(i)); 57 } 58 printf("\n"); 59 } 60 return 0; 61 }