Color the ball
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
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
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 100008
#define lid (id<<1)//左
#define rid (lid|1)//右
typedef long long LL;
struct node
{
int l,r;//左右边界
LL sum;//表示的和
int lazy;//延迟标记
}tr[N*4];
int val=1;//添加的值
void build(int l,int r,int id)//从上到下建立一棵树
{
tr[id].l = l; tr[id].r = r;//左右边界赋值
tr[id].sum = 0;//和赋值
tr[id].lazy = 0;//延迟标记清零
if( l == r )
return ;//结束条件别忘了
int mid=(tr[id].l+tr[id].r)>> 1;//中点
build(l,mid,lid);//左边
build(mid+1,r,rid);//右边
}
void push_up(int id)//向上传递
{
tr[id].sum = tr[lid].sum + tr[rid].sum;//一个结点的值等于它左右两边的和
}
void push_down(int id)//向下分解
{
int m=tr[id].r-tr[id].l+1;//类似这个结点的长度
if(tr[id].lazy)//延迟标记不为0
{
tr[lid].lazy+=tr[id].lazy;//延迟标记传给左边
tr[rid].lazy+=tr[id].lazy;//延迟标记传给右边
tr[lid].sum+=tr[id].lazy*(m-(m>>1));
//左边的值等于它本身加上 添加的值乘长度的一半(也可以理解为它本身的长度)
tr[rid].sum+=tr[id].lazy*(m>>1);
//右边同理 只不过是剩下的一半
tr[id].lazy=0;//注意 分解之后 延迟标记一定要变回0
}
}
void updata(int a,int b,int id)//更新区间内的值
{
if(tr[id].l>=a&&tr[id].r<=b)//恰好是要更新的范围
{
tr[id].lazy+=val;//延迟标记加上更新值
tr[id].sum+=val*(tr[id].r-tr[id].l+1);//此结点值变为它本身加上它所包含的长度
return ;
}
else
{
push_down(id);//向下分解
int mid=(tr[id].l+tr[id].r)>> 1;//中点
if(a>mid)//区间起点大于中点
{
updata(a,b,rid);//全部在右边 更新右
}
else if(b<=mid)//区间终点小于等于终点
{
updata(a,b,lid);//全部在左边 更新左
}
else//两边都有
{
updata(a,b,rid);
updata(a,b,lid);
}//都更新
}
push_up(id);//向上传递
}
LL query(int a,int b,int id)//查询区间值
{
if(tr[id].l>=a&&tr[id].r<=b)//恰好是要查询的区间
return tr[id].sum;//直接返回值
else
{
push_down(id);//查询时也别忘了分解
int mid=(tr[id].l+tr[id].r)>> 1;//中点
if(a>mid)//全在右 查询右
{
return query(a,b,rid);
}
else if(b<=mid)//全在左 查询左
{
return query(a,b,lid);
}
else//都有 返回两边的和
{
return query(a,b,rid)+query(a,b,lid);
}
}
}
int main()
{
int n;
while(cin>>n)
{
if(n==0)
break;
build(1,n,1);
for(int i=1;i<=n;i++)
{
int a,b;
cin>>a>>b;
updata(a,b,1);
}
for(int i=1;i<n;i++)
{
printf("%I64d ",query(i,i,1));
}
printf("%I64d\n",query(n,n,1));//别忘了long long注意下格式
}
return 0;
}
顺便推荐一篇写的比较详细的线段树知识点的文章。
线段树入门(二):http://www.cnblogs.com/shadowland/p/5870354.html