Color the ball
Time Limit:3000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
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,输入结束。
当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
思路:
这题就是将末端的数加一后的不断+lowbit()后面的数减一,为什么?举个栗子:假如在2 4之间,那2与4都要更新1,
一直更新到最大的气球数为止。而2就不断更1,4就加一为5后不断减一,这样就形成了一个【2,4】的区间了。再加5 6进来。
那5要更新1,六要更新1,之后就一增一降就抵消了。那5从2,4就为-1了,再加1就变了0.所以它再加点4那个1值就为一了。
(凡是从奇数变了偶数,都只会加偶数)
树状数组:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int cnt[100010],n;
int lowbit(int x)
{
return x&(-x);
}
void update(int i, int j)
{
while (i<=n)
{
cnt[i]+=j;
i+=lowbit(i);
}
}
int sum(int i)
{
int t=0;
while (i>0)
{
t+=cnt[i];
i-=lowbit(i);
}
return t;
}
int main()
{
int m,i,k,j;
while(~scanf("%d",&n)&&n)
{
memset(cnt,0,sizeof(cnt));
j=n;
while (j--)
{
scanf("%d %d",&m,&k);
update(m,1);
//线段树是只要更新2的n次方的数就行了,所以要控制他的范围
update(k+1,-1);
}
printf("%d",sum(1));
for(i=2;i<=n;i++)
printf(" %d",sum(i));
printf("\n");
}
return 0;
}