首页 > 代码库 > HDU - 1556 Color the ball(线段树和树状数组)

HDU - 1556 Color the ball(线段树和树状数组)

题意:n个气球,n个操作(每次给区间[a,b]的气球涂颜色),求最后每个气球被涂颜色的次数。

n可以取到100000,所以如果想for,for的话,就 爆!爆!爆!

1.线段树做法:

一道简单的线段树,做了好久都没做出来,果然自己还是太菜了。。。

创建一棵线段树,把里面的涂色次数对应的值都初始化为0。

更新的时候,找到那个要涂色的区间,涂色次数+1。

询问的时候从上往下找到那个区间,每次把值都递归出来。

 1 #define LC(a) ((a<<1)+1)
 2 #define RC(a) ((a<<1)+2)
 3 #define MID(a,b) ((a+b)>>1)
 4 #include <stdio.h>
 5 
 6 struct node{
 7     int l,r;
 8     int mid;
 9     int val;
10 };
11 
12 const int maxn=111111;
13 node T[maxn*4];
14 
15 void create(int p,int l,int r){
16     T[p].l=l,T[p].r=r,T[p].mid=MID(l,r),T[p].val=0;//初始化所有的val都为0 
17     if(l==r) return ;//如果找到最下面就退出
18     create(LC(p),l,T[p].mid);
19     create(RC(p),T[p].mid+1,r);
20 }
21 
22 void update(int p,int l,int r){
23     if(T[p].l==l&&T[p].r==r){//找到这个节点,+1,递归出口 
24         T[p].val++;
25         return ; 
26     }
27     if(T[p].l==T[p].r) return ;//没找到这个节点,递归出口,特殊情况的出口 
28     if(T[p].mid>=r) update(LC(p),l,r);//往左子树找 
29     else if(T[p].mid<l) update(RC(p),l,r);//右子树找 
30     else{                                //如果是分开的区间,两边都要找 
31         update(LC(p),l,T[p].mid);
32         update(RC(p),T[p].mid+1,r);
33     }
34 }
35 
36 int query(int p,int l,int r){
37     if(T[p].l==l&&T[p].r==r) return T[p].val;//如果找到这个区间,就返回。递归,之前的值也都加上来了 
38     if(T[p].l==T[p].r) return 0;//特殊情况的出口 
39     if(r<=T[p].mid) return query(LC(p),l,r)+T[p].val;
40     else if(l>T[p].mid) return query(RC(p),l,r)+T[p].val;
41     else return query(LC(p),l,T[p].mid)+query(RC(p),T[p].mid+1,r)+T[p].val; 
42 }
43 
44 int main(){
45     int n,a,b;
46     while(scanf("%d",&n)!=EOF&&n!=0){
47         create(0,1,n);
48         for(int i=1;i<=n;i++){
49             scanf("%d %d",&a,&b);
50             update(0,a,b);
51         }
52         for(int i=1;i<=n;i++){
53             int sum=query(0,i,i);
54             printf("%d",sum);
55             if(i!=n) printf(" ");
56         }
57         printf("\n");
58     }
59     return 0;
60 }

 2.树状数组做法:

 

HDU - 1556 Color the ball(线段树和树状数组)