HDU -1556 Color the ball -线段树-成段更新

来源:互联网 发布:剑网三男神捏脸数据 编辑:程序博客网 时间:2024/04/29 21:20

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个气球编号分别为123……n进行上色,每次上色为一个区间a~b,问n次操作后,每个气球分别被上色多少次。

分析:

用线段树做,只需要每次更新都适当地做标记,最后将所有标记都下沉至叶子结点,此时,叶子结点的标记值便是该气球被上色的次数,直接输出各个叶子结点的值即可。

说一下我对标记下沉的理解,以此题为例,假设有如下数据:

5

1 3 ——①

1 2 ——②

1 1 ——③

1 4 ——④

1 5 ——⑤

那么操作流程分别为

建树:


可得pos_rt[0]=8,pos_rt[1]=9, pos_rt[2]=5, pos_rt[3]=6, pos_rt[4]=7

而后更新:

① [1 3]做标记,sign[2]++



② [1 2]做标记,[1 3]标记下沉:sign[4]+=sign[2],sign[5]+=sign[2],sign[4]++;sign[2]=0;



③ [1 1]做标记,[1 2]标记下沉: sign[8]+=sign[4],sign[9]+=sign[4],sign[8]++;sign[4]=0;



④ [1 4]做标记,标记[1 3][4 4]



⑤ [1 5]做标记



此时标记全都做完了,然后对所有标记进行下沉到叶子结点



输出每个叶子结点的标记,及每个气球的上色次数。

代码:

 #include <iostream> #include <stdio.h> #include <stdlib.h>  using namespace std; int pos_rt[100001];//用来记录气球编号对应的下标rt int sign[400000];//各rt的标记 int size;//气球的编号个数 void _build(int l,int r,int rt)//建树(其实我的建树只是用来查找记录气球编号的rt的)  {     if(l==r)     {         pos_rt[size++]=rt;//找到叶子结点时,记录下rt,以便输出         return;     }     int m=(l+r)>>1;     _build(l,m,rt<<1);     _build(m+1,r,rt<<1|1);  } void _downUpDate(int rt)//标记下沉  {     if(sign[rt])//当有标记时     {         sign[rt<<1]+=sign[rt];//左子树标记更新         sign[rt<<1|1]+=sign[rt];//右子树标记更新         sign[rt]=0;//删除当前rt的标记     }  } void _upDate(int L,int R,int l,int r,int rt)//用以更新下沉标记  {     if(L<=l&&r<=R)//区间包含,当前区间的标记+1     {         sign[rt]++;         return;     }     _downUpDate(rt);//当前rt被用到,故下沉标记到左右子树     int m=(l+r)>>1;     if(L<=m)         _upDate(L,R,l,m,rt<<1);     if(R>m)         _upDate(L,R,m+1,r,rt<<1|1);   } void _pushDown(int l,int r,int rt)//所有标记下沉至叶子结点  {     if(l==r)//叶子结点回溯         return;     _downUpDate(rt);//非叶子结点下沉标记     int m=(l+r)>>1;     _pushDown(l,m,rt<<1);     _pushDown(m+1,r,rt<<1|1);  } int main()  {     int n,a,b,i;     while(scanf("%d",&n),n)     {         size=0;         memset(pos_rt,0,sizeof(pos_rt));         memset(sign,0,sizeof(sign));         _build(1,n,1);         for(i=0;i<n;i++)         {             scanf("%d%d",&a,&b);             _upDate(a,b,1,n,1);         }         _pushDown(1,n,1);         for(i=0;i<size-1;i++)//直接输出各叶子结点的标记的值,对应的rt已用pos_rt数组记录             printf("%d ",sign[pos_rt[i]]);         printf("%d\n",sign[pos_rt[size-1]]);     }     return 0;  } 

原创粉丝点击