HDU 1556 树状数组

Color the ball

Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15081    Accepted Submission(s): 7508

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

题意是很好理解的,有两种方法来实现,一个是线段树,另一个就是树状数组,刚好当一次入门的树状数组的入门题

这里用一个一位数组来模拟涂气球的所有的情况,首先我们要知道树状数组是向上更改,向下求和的

树状数组是解决区间问题的,拿n=8来说,当涂1--3时,在树状数组是从前向后遍历,从c[1]->c[2]->c[4]->c[8](到达最大值)

我们需要改变的是1--3的区间值,所以还要减去c[3+1]->c[8]这样不就将所需要的区间值改变了。题目要求将每个节点所涂的次数输出,比如输出5的值,由上图可知,5处 的值就是c[5],要求4的值,那就需要向前遍历一遍,将每个节点上的值加起来,就是所要求的值(下面的A[1]--A[8]只是起一个辅助理解的作用,这个A数组在代码中是不体现的),还有就是这道题目卡输出格式!!!c数组只是一个前缀和,你单点查询的时候所得到的值就是你1--i的区间所涂的次数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=10000;
ll n;
int c[100005];
int lowbit(int a)
{
    return a&(-a);
}
void add(int a ,int k)
{
    int i=a;
    while(i<=n)
    {
        c[i]+=k;
        i+=lowbit(i);
    }
}
int sum(int x)
{
    int sum=0;
    for(int i=x;i;i-=lowbit(i)) sum+=c[i];
    return sum;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    while(cin>>n&&n){
            memset(c,0,sizeof c);
    int a,b;
    int m=n;
    while(m--)
        {
         cin>>a>>b;
         add(a,1);
         add(b+1,-1);
        }
         for(int i=1;i<n;i++)
            cout<<sum(i)<<" ";//并不表示i这个点,表示的是一次性涂1--i这个区间所的次数
        cout<<sum(n)<<endl;//比如涂1--2再涂1--2,再1--3那么sum(2)表示1--2这个区间涂过两次
    }//sum(3)表示1--3这个区间一次性只涂过一次
    return 0;
}

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/81634942
今日推荐