hdoj 1556 Color the ball【线段树区间更新】
Color the ball
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13072 Accepted Submission(s):
6537
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,输入结束。
当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
Author
8600
#include<stdio.h> #include<string.h> #include<queue> #include<algorithm> #define MAX 100010 #define INF 0x3f3f3f int n,m; int sum[MAX<<2];//记录每个区间的值,即每个气球被标记的次数 int add[MAX<<2];//记录每个对应区间的每个数的值 int ans; void pushup(int o)//向上传递用来更新每一次被标记区间的值 的改变 { sum[o]=sum[o<<1]+sum[o<<1|1]; } void pushdown(int o,int m)//向下传递 { if(add[o]) { add[o<<1]+=add[o]; add[o<<1|1]+=add[o]; sum[o<<1]+=add[o]*(m-(m>>1));//线段树左分支的区间长度等于右分支或者比右分支大1 sum[o<<1|1]+=add[o]*(m>>1); add[o]=0; } } void gettree(int o,int l,int r)//建树 { sum[o]=add[o]=0; if(l==r) return ; int mid=(l+r)>>1; gettree(o<<1,l,mid); gettree(o<<1|1,mid+1,r); pushup(o); } void update(int o,int l,int r,int L,int R) { if(L<=l&&R>=r) { add[o]+=1; sum[o]+=1*(r-l+1); return ; } pushdown(o,r-l+1); int mid=(l+r)>>1; if(L <= mid) update(o<<1, l, mid, L ,R); if(R > mid) update(o<<1|1, mid+1, r, L ,R); pushup(o);//维护区间的值 } int find(int o,int l,int r,int L,int R)//查找每个气球被修改次数并输出 { if(L<=l&&R>=r) { return sum[o]; } pushdown(o,r-l+1); int ans=0; int mid=(r+l)>>1; if(L<=mid) ans+=find(o<<1,l,mid,L,R); if(R>mid) ans+=find(o<<1|1,mid+1,r,L,R); return ans; } int main() { int i,j,a,b; while(scanf("%d",&n),n) { gettree(1,1,n); for(i=1;i<=n;i++) { scanf("%d%d",&a,&b); update(1,1,n,a,b); } for(i=1;i<=n;i++) { if(i>1) printf(" "); printf("%d",find(1,1,n,i,i)); } printf("\n"); } return 0; }