线段树、前缀数组:HDU1591-Color the ball(区间更新、简单题)

Color the ball

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

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


解题心得:

  1. 这个题可以用一个前缀数组就可以过了,给你两个数s和e,里面的所有的气球的颜色改变,可以创建一个数组num,长度为n,将num[s]++,num[e+1]–,然后用sum将前面的数加起来就好了,直接看代码吧。
  2. 这个题还可以使用线段树来写,先建立一个线段树,时间是logn,将每个区间维护更新,维护一次的时间是logn,最后再输出时间还是logn。在更新的时候只要找到最前面的一个区间就可以了,不用在找到了一个区间的还继续将下面的子节点继续更新,因为在最后输出的时候只要从起点开始向下面的数找就行了,有一个就加一个就行了。(我的线段树跑了967ms,额)

前缀数组

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
int num[maxn];
int main()
{
    int n;
    while(scanf("%d",&n) && n)
    {
        memset(num,0,sizeof(num));
        int N = n;
        while(N--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            //前缀数组
            num[a] ++;
            num[b+1]--;
        }
        int sum = 0;
        sum += num[1];
        printf("%d",sum);
        for(int i=2;i<=n;i++)
        {
            sum += num[i];
            printf(" %d",sum);
        }
        printf("\n");
    }
    return 0;

线段树

/*
这个虽然是区间更新,但是在最后输出的只是一个点的值
所以在更新可以是区间更新,但是输出还是点的输出
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
struct node
{
    int l,r,num;
}tree[maxn*4];

//先建一个线段树
void build_tree(int l,int r,int root)
{
    int mid;
    tree[root].l = l;
    tree[root].r = r;
    tree[root].num = 0;
    if(l == r)
        return;
    mid = (l + r) / 2;
    build_tree(l,mid,root*2);
    build_tree(mid+1,r,root*2+1);
}

//每一次区间更新
int pushup(int l,int r,int root)
{
    int mid;
    if(tree[root].l == l && tree[root].r == r)
    {
        tree[root].num ++;
        return 0;
    }
    mid = (tree[root].l + tree[root].r) / 2;
    if(r <= mid)
        return pushup(l,r,root*2);
    else if(l > mid)
        return pushup(l,r,root*2+1);
    else
    {
        pushup(l,mid,root*2);
        pushup(mid+1,r,root*2+1);
    }
}

//最后从根节点找答案
int Ans(int pos,int root,int ans)
{
    int mid;
    if(tree[root].l > pos || tree[root].r < pos)//找歪了,顺便剪个枝
        return ans;
    if(tree[root].num)
        ans += tree[root].num;
    if(tree[root].l == tree[root].r)
        return  ans;
    mid = (tree[root].l + tree[root].r) / 2;
    if(pos <= mid)
        return Ans(pos,root*2,ans);
    else if(pos > mid)
        return Ans(pos,root*2+1,ans);
}

int main()
{
    int n;
    while(scanf("%d",&n) && n)
    {
        build_tree(1,n,1);
        int N = n;
        while(N--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            pushup(a,b,1);
        }
        printf("%d",Ans(1,1,0));
        for(int i=2;i<=n;i++)
        {
            printf(" %d",Ans(i,1,0));
        }
        printf("\n");
    }
}
posted @ 2017-07-22 19:23  GoldenFingers  阅读(84)  评论(0编辑  收藏  举报