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;
}

(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;
}

时间: 2024-10-13 19:54:07

HDU 1556 线段树或树状数组,插段求点的相关文章

Codeforces 390E Inna and Large Sweet Matrix 树状数组改段求段

题目链接:点击打开链接 题意:给定n*m的二维平面 w个操作 1.0 (x1,y1) (x2,y2) value for i : x1 to x2 for j : y1 to y2 mp[i][j] += value; 2.1 (x1, y1) (x2 y2) ans1 = 纵坐标在 y1,y2间的总数 ans2 = 横坐标不在x1,x2间的总数 puts(ans1-ans2); 因为n最大是4e6, 所以用树状数组改段求段代替线段树 #include <stdio.h> #include &

HDU 1556 数据结构-树状数组-改段求点

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1556 解题思路:树状数组,只要了解树状数组的原理就不用死记模板了,总之树状数组管理的就是前缀和,高度越高的的结点管理的范围越广 所以要是改点求段:更改一个点就要向上传递 所以要是改段求点:更改一个点就要向下传递 代码: #include <cstdio> #include <iostream> #include <cstring> using namespace std;

CodeForces 390E Inna and Large Sweet Matrix(树状数组改段求段)

树状数组只能实现线段树区间修改和区间查询的功能,可以代替不需要lazy tag的线段树,且代码量和常数较小 首先定义一个数组 int c[N]; 并清空 memset(c, 0, sizeof c); 1.单点修改 : c[x] += y; 对应的函数是 change(x, y); 2.求前缀和 :  对应的函数是 int sum(x) 两种操作的复杂度都是O(logn) 模板如下: int c[N], maxn; inline int Lowbit(int x){return x&(-x);}

树状数组改点求段

#include<stdio.h> int a[20],n; int lowbit(int x) { return x&(-x); } void add(int x,int c) { int i; for(i=x; i<=n; i+=lowbit(i))a[i]+=c; } int sum(int x) { int s=0,i; for(i=x; i; i-=lowbit(i))s+=a[i]; return s; } int main() { scanf("%d&qu

树状数组成段更新——POJ 3468

A Simple Problem with IntegersCrawling in process... Crawling failed Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3468 Description You have N integers, A1, A2, ... , AN. You need to deal wit

HDU 1556 Color the ball(树状数组)(填坑)

题目地址:HDU 1556 因为听别人说树状数组能做的线段树都可以,所以也一直没学,但是现在遇到好多题卡线段树...跪了..所以就学一下填填坑. 这题应该是树状数组的入门题了.不多说了. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #in

HDU 1556 Color the ball 树状数组

Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10150    Accepted Submission(s): 5161 Problem Description N 个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从

【初识——树状数组】 区间求最值

说树状数组其实是一个索引表,但是是一个特殊的,树状的索引表,它利用了二进制的一些特性. 就区间求和的要求来说: 首先我们用a[]数组来存储原始数据.然后在a[]之上构造c[]数组来作为树状数组. 如图 这个图表示,当i为奇数时,c[i]中保存的都是a[i]本身.然后,c[2]中保存了a[1], a[2],共2个,c[4]中保存的是a[1], a[2], a[3], a[4],c[6]又是保存两个,c[5]和c[6].c[8]保存8个,c[1], c[2], c[3], c[4], c[5], c

【树状数组】段修改,点查询

利用差分,先得到一个差分序列(如:(1,2,3,5)的差分序列为(1,1,1,2)) 当[i,j]段中所有数均加上数m时,在差分序列的i位置加上m,在j+1位置减去m即可 求和利用树状数组 以下是pascal程序: var a,fai:array[0..1000] of longint; c:char; n,i,x,y,f,m:longint; function lowbit(x:longint):longint; begin lowbit:=x and (-x); end; procedure