hdu 1556 Color the ball 线段树,树状树组,与dp思想的树组解决技巧

 来源: http://acm.hdu.edu.cn/showproblem.php?pid=1556;

Color the ball

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


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 这个题目在我们学校(ecjtu)比赛时没做出来,因为当时只学会了线段树单点更新与区间求和。 后来赛后连续做了两天的线段树,,,线段树水很深,我至今都还有很多技巧没有掌握,大家好好努力吧。 首先来看线段树代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define mem(str,x)  memset(str,(x),sizeof(str))
#define mid (l+r)>>1
#define len (r-l+1)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn=100010;
int sum[maxn<<2],root[maxn<<2],n;

inline void pushup(int rt){
   sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
inline void pushdown(int rt,int _len){
    if(root[rt]){
        int l=rt<<1,r=rt<<1|1,m=_len>>1;
        root[l] += root[rt];
        root[r] += root[rt];
        sum[l]  += (_len-m)*root[rt];
        sum[r]  +=m*root[rt];
        root[rt] = 0;
    }
}
void update(int left,int right,int l,int r,int rt)
{
    if(left<=l && right>=r){
        ++root[rt];
        sum[rt] += len;
        return ;
    }
    pushdown(rt,len);
    int m = mid;
    if(left<=m) update(left,right,lson);
    if(right>m) update(left,right,rson);
    pushup(rt);
}
int query(int left,int right,int l,int r,int rt)
{
    if(left==l && right==r) return sum[rt];
    int m = mid;
    pushdown(rt,len);
    int s;
    if(left<=m) s=query(left,right,lson);
    else if(right>m) s=query(left,right,rson);
    else s=(query(left,m,lson)+query(m+1,right,rson));
  return s;
}
int  main()
{
    int a,b;
    while(~scanf("%d",&n)&&n){
        mem(sum,0);mem(root,0);///相当于建树的初始化。
        for(int i=0;i<n;i++){
            scanf("%d%d",&a,&b);
            update(a,b,1,n,1);
        }
        for(int i=1;i<=n;i++){
            printf("%d%c",query(i,i,1,n,1),i==n?'\n':' ');
        }
    }
    return 0;
}


下面是树状树组的代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 100000+10
int s[maxn];

int lowbit(int x)
{
    return x&(-x);
}

void update(int x,int c,int n)
{
    while(x<=n){
        s[x]+=c;
        x+=lowbit(x);
    }
}

int getsum(int x)
{
    int sum=0;
    while(x>0){
            sum+=s[x];
            x-=lowbit(x);
    }
    return sum;
}

int main()
{
    int N;
    while(scanf("%d",&N),N)
    {
        memset(s,0,sizeof(s));
        for(int i=1;i<=N;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            update(a,1,N);
            update(b+1,-1,N);
        }
        for(int i=1;i<=N;i++){
            printf("%d%c",getsum(i),i==N?'\n':' ');
        }
    }
    return 0;
}

下面是数组解决法(用到了dp思想):
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace  std;
#define maxn 100000+10
int s[maxn];
int main()
{
    int N;
    while(scanf("%d",&N),N){
            memset(s,0,sizeof(s));
       for(int i=1;i<=N;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        s[a]++;
        s[b+1]--;
       }
       for(int i=1;i<=N;i++){
        s[i]+=s[i-1];
        printf("%d%c",s[i],i==N?'\n':' ');
       }
    }
    return 0;
}





 

你可能感兴趣的:(树状数组,线段树成段更新)