线段树 (更新区间查询点)Color the ball

系统管理员 2022-06-07 02:40 287阅读 0赞

Color the ball

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

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

  1. 3
  2. 1 1
  3. 2 2
  4. 3 3
  5. 3
  6. 1 1
  7. 1 2
  8. 1 3
  9. 0

Sample Output

  1. 1 1 1
  2. 3 2 1

Author

8600

Source

HDU 2006-12 Programming Contest

Recommend

LL

代码:

#include
#include add[] sum[] //清零
using namespace std;
typedef long long ll;
#define MAX 100000+10
struct node
{
ll l,r;
ll mid() //中点
{
return (l+r)>>1;
}
}num[MAX<<2\]; ll sum\[MAX<<2\],add\[MAX<<2\]; //一般都向右移动 2 void build(ll l,ll r ,ll rt) //构建线段树 \{ num\[rt\].l=l; //先给线段树的左右赋值 num\[rt\].r=r; add\[rt\]=0; if(l==r) //如果要构建的线段树的左右相等 说明已经建到底了 就跳出 \{ return ; \} build(l,num\[rt\].mid(),rt<<1);//左下建树 build(num\[rt\].mid()+1,r,rt<<1|1);//右下建树 \} void PushDown(ll rt,ll m)//向下扩展 \{ if(add\[rt\])// 当此时节点有要加的数时 就是有倍数时 此节点左子节点 右子节点 都在原有的基础上倍数加倍数 总数等于区间长度乘倍数 \{ add\[rt<<1\]+=add\[rt\]; add\[rt<<1|1\]+=add\[rt\]; sum\[rt<<1\]+=add\[rt\]\*(m-(m>>1));
sum[rt<<1|1\]+=add\[rt\]\*(m>>1);
add[rt]=0;// 最后把现在节点 要增加的数赋0
}
}
void PushUp(ll rt)// 向上扩展(说明此时节点不是最低层)
{
sum[rt]=sum[rt<<1\]+sum\[rt<<1|1\];// 此节点的和等于左子节点和右子节点的和 \} void update(ll l,ll r,ll rt)// 更新 此题每更新一次add加一 都是固定的 所以此时就传了三个参数 一般传四个 \{ if(num\[rt\].l==l&&num\[rt\].r==r) //如果此节点就是要更新的节点 \{ add\[rt\]++; //此节点的加倍数+1 sum\[rt\]+=(num\[rt\].r-num\[rt\].l+1)\*1; //此节点的和等于区间长度\*1 return; \} // 不满足时 PushDown(rt,num\[rt\].r-num\[rt\].l+1); // 向下扩展一级 ll m=num\[rt\].mid();// 得此时节点的中点 if(r<=m) \{ update(l,r,rt<<1); \} else if(l>m)
{
update(l,r,rt<<1|1); \} else \{ update(l,m,rt<<1); update(m+1,r,rt<<1|1); \} PushUp(rt);// 最后再向push rt一定不是低节点 rt为要更新节点的上一级或最低节点的上一级 \} ll query(ll l,ll r,ll rt) // 查询 返回查询到的总和 \{ if(num\[rt\].l==l&&num\[rt\].r==r)// 如果查询到就返回此时节点的总和 \{ return sum\[rt\]; \} // 如果查询不到 PushDown(rt,num\[rt\].r-num\[rt\].l+1); //向下扩展一级 ll res=0;// 声明累加总和 ll m=num\[rt\].mid(); //得中点 if(r<=m) \{ res+=query(l,r,rt<<1); \} else if(l>m)
{
res+=query(l,r,rt<<1|1); \} else \{ res+=query(l,m,rt<<1); res+=query(m+1,r,rt<<1|1); \} return res; \} int main() \{ int n; while(cin>>n)
{
if(n==0)
{
break;
}
build(1,n,1);
int m=n;
while(m—)
{
int a,b;
cin>>a>>b;
update(a,b,1);
}
int i;
for(i=1;i<n;i++)
{
cout<<query(i,i,1)<<” “;
}
cout<<query(n,n,1)<<endl;
memset(add,0,sizeof(add));
memset(sum,0,sizeof(sum));
}
return 0;
}

发表评论

表情:
评论列表 (有 0 条评论,287人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线段区间更新

    线段树成段更新延迟标记理解 区间更新是指每次更新的时候更新的是一个区间里面的所有值,例如将区间\[l,r\]内的所有点都加或者减去一个数,或者替换成一个数字等等.因为区间更新