HDU

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

解题思路:本题可以想到三种方法,暴力, 线段树, 树状数组。暴力的话复杂度为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("
");
59     }
60     return 0;
61 }



 
原文地址:https://www.cnblogs.com/Lightfall/p/9307780.html