HDU 1556 线段树或树状数组,插段求点

Posted 掉血菜鸡煮熟中

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 1556 线段树或树状数组,插段求点相关的知识,希望对你有一定的参考价值。

1、HDU 1556  Color the ball   区间更新,单点查询

2、题意:n个气球,每次给(a,b)区间的气球涂一次色,问最后每个气球各涂了几次。

(1)树状数组

总结:树状数组是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值。

这里改下思路可以用树状数组。在更新(a,b)时,向上更新,将a~n加1,b+1~n减1。查询点时,向下求和即可。

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstdio>
#define F(i,a,b) for (int i=a;i<b;i++)
#define FF(i,a,b) for (int i=a;i<=b;i++)
#define mes(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=10010,MAX=100100;

int n,c[MAX];

int lowbit(int x) {
    //计算2^k
    return x&-x;
}

void update(int x,int val)
{
    //向上更新,使所有包含了x的区间都更新一下
    while(x<=n) {
        c[x]+=val;
        x+=lowbit(x);
    }
}

int Sum(int x)
{
    //向下查询
    int sum=0;
    while(x>0) {
        sum+=c[x];
        x-=lowbit(x);
    }
    return sum;
}

int main()
{
    while(~scanf("%d",&n),n) {
        mes(c,0);
        int a,b;
        FF(i,1,n) {
            scanf("%d%d",&a,&b);
            update(a,1);
            update(b+1,-1);
        }
        F(i,1,n) printf("%d ",Sum(i));
        printf("%d\\n",Sum(n));
    }

    return 0;
}
View Code

 (2)线段树+lazy思想

总结:lazy,更新时只到区间,可以节省很多时间。

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstdio>
#define F(i,a,b) for (int i=a;i<b;i++)
#define FF(i,a,b) for (int i=a;i<=b;i++)
#define mes(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=10010,MAX=100010;

int n,c[MAX<<2];

void build(int o,int L,int R)
{
    c[o]=0;
    if(L==R) return ;
    int mid=(L+R)>>1;
    build(o<<1,L,mid);
    build(o<<1|1,mid+1,R);
}

void update(int o,int l,int r,int L,int R)
{
    if(l<=L&&R<=r) { c[o]++; return ; }     //关键:只更新到区间,一开始更新到每个单独的点,果断T了,//然后用l==L&&R==r,又果断MLE
    int mid=(L+R)>>1;
    if(mid<l) update(o<<1|1,l,r,mid+1,R);
    else if(r<=mid) update(o<<1,l,r,L,mid);
    else {
        update(o<<1,l,r,L,mid);
        update(o<<1|1,l,r,mid+1,R);
    }
}

int ans[MAX];
void query(int o,int L,int R)
{
    if(c[o]) {
        for(int i=L; i<=R; i++)
            ans[i]+=c[o];   //也是lazy思想,标记了的区间就加上
    }
    if(L==R) return ;   //询问时还是要到点
    int mid=(L+R)>>1;
    query(o<<1,L,mid);
    query(o<<1|1,mid+1,R);
}

int main()
{
    while(~scanf("%d",&n) ,n )
    {
        build(1,1,n);
        fill(ans+1,ans+1+n,0);       //fil函数
        int a,b;
        FF(i,1,n) {
            scanf("%d%d",&a,&b);
            update(1,a,b,1,n);
        }
        query(1,1,n);
        F(i,1,n) printf("%d ",ans[i]);
        printf("%d\\n",ans[n]);
    }

    return 0;
}
View Code

以上是关于HDU 1556 线段树或树状数组,插段求点的主要内容,如果未能解决你的问题,请参考以下文章

树状数组的改段求点,改段求段

树状数组模板(改点求段 / 该段求点 / 改段求段)

HDU 1166 敌兵布阵(线段树或树状数组)

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

HDU1556-Color the ball-前缀和/线段树/树状数组

HDU 1556 Color the ball(线段树:区间更新)