hdu1556树状数组&&线段树2种做法

Color the ball
Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 10   Accepted Submission(s) : 3
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



线段树:  注意必须用LAZY思想 否则必死

#include<stdio.h>
struct haha
{
    int left;
    int right;
    int cover;
}node[100000*4];
int cnt,n;
void build(int left,int right,int nd)
{
    node[nd].left=left;
    node[nd].right=right;
    node[nd].cover=0;
    if(left==right) return ;
    int mid=(node[nd].left+node[nd].right)/2;
    build(left,mid,nd*2);
    build(mid+1,right,nd*2+1);
}
void push(int nd)
{
    if(node[nd].left==node[nd].right) return;
    if(node[nd].cover)
    {
        node[nd*2].cover+=node[nd].cover;//我一  这个地方是加 不是直接附值
        node[nd*2+1].cover+=node[nd].cover;
        node[nd].cover=0;
    }
    return ;
}
void update(int left,int right,int nd)
{
    if(node[nd].left==left&&node[nd].right==right)
    {
        node[nd].cover++;
        push(nd);
        return;
    }
    int mid=(node[nd].left+node[nd].right)/2;
    if(right<=mid) update(left,right,nd*2);
    else if(left>mid) update(left,right,nd*2+1);
    else
    {
        update(left,mid,nd*2);
        update(mid+1,right,nd*2+1);
    }
    push(nd);
}
void query(int nd)
{
    push(nd);
    if(node[nd].left==node[nd].right)
    {
        if(cnt!=n)
            printf("%d ",node[nd].cover);
        else printf("%d\n",node[nd].cover);
        cnt++;
        return ;
    }
    query(nd*2);
    query(nd*2+1);
}
int main()
{
    int i;
    while(scanf("%d",&n)&&n!=0)
    {
        cnt=1;
        build(1,n,1);
        for(i=1;i<=n;i++)
        {
            int s,e;
            scanf("%d %d",&s,&e);
            update(s,e,1);
        }
        query(1);
    }
    return 0;
}

树状数组
#include<stdio.h>
#include<string.h>
int c[100000+5],n;
int Lowbit(int k)
{
    return (k&-k);
}
void update(int pos,int num)
{
    while(pos<=n)
    {
        c[pos]+=num;
        pos+=Lowbit(pos);
    }
}
int sum(int pos)
{
    int s=0;
    
    while(pos>0)
    {
        s+=c[pos];
        pos-=Lowbit(pos);
    }
    return s;
}
int main()
{
    int i,j,s,e;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        memset(c,0,(n+3)*sizeof(c[0]));
        for(i=1;i<=n;i++)
        {
            scanf("%d %d",&s,&e);
            update(s,1);
            update(e+1,-1);
        }
        for(i=1;i<n;i++)
            printf("%d ",sum(i));
        printf("%d\n",sum(i));
    }
    return 0;
}

针对上面的插线问点。。。有两种求解办法。。

对于区间a——b:如果插入一个数1

第一种:update(a,1)和update(b+1,-1) 查询方式直接Quary(p)

第二种:for(int i=a;i<=b;++i) update(i,1) 查询方式Quary(p)-Quary(p-1);

一般人都用第一种更新方法。。。

其实上面那种方法  就是    举个例子吧

数组:

0    0    0     0     0      0    0     0      0   数组内容

0    1    2      3    4      5    6     7      8   数组编号

2-4染了一次后变成了

0    1    0     0     0      -1    0     0      0   数组内容

0    1    2      3    4      5    6     7      8   数组编号

3-7染了一次后

0    1    0     1    0     -1   0     0      -1   数组内容

0    1   2      3    4      5    6     7      8   数组编号

那么查询3的时候就是 3及其之前所有元素的和 2    (这就是数组数组中的查询sum操作)

查询6的时候就是6及其之前的所有元素和1   

你可能感兴趣的:(c,测试,query,input,Build,output)