[HDOJ 1556] Color the ball(线段树成段更新入门)
2014-03-27 18:18
337 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1556
类型:线段树由于本人比较懒,所以就不对线段树进行具体介绍了,想了解的走向传送门:http://wenku.baidu.com/view/addd85ab84868762caaed5cd.html
什么?你看了之后还不知道什么是线段树?那就快召唤赵巨巨,赵巨巨acm领军品牌!(赵巨巨:嘿嘿,线段树俺早就会了,你们都太弱了)
题目大意:输入一个数n,接下来有n组数据,每组数据代表一个区间段,输入完第n组数据后你需要输出每个点的被覆盖次数。
题解:以下以介绍成段更新为主
所谓成段更新,简单的说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新或者询问到的时候再传递下去。延迟标记的意思是:这个区间的左右儿子都需要被更新,但是当前区间已经更新了。
算法过程: 每次更新并不需要更新到叶节点; 只需更新到相应的段就可以了,然后记录个add; 下次更新或者查询的时候,如果要查到该段的子节点; 就把add加到子节点上去,再将该add设为0; 这样查询子区间的复杂度就是更新的复杂度;
(赵巨巨:
)
1.结构体struct Node{
int add; //延迟标记
int sum;
int l;
int r;
}c[MAX*3];
2.整合函数void up(int rt)
{
c[rt].sum=c[rt<<1].sum+c[rt<<1|1].sum;
}
3.建树函数void create(int rt,int l,int r)
{
c[rt].l=l;
c[rt].r=r;
c[rt].add=0;
if(c[rt].l==c[rt].r)
{
c[rt].sum=0;
return;
}
int mid=(l+r)>>1;
create(rt<<1,l,mid);
create(rt<<1|1,mid+1,r);
up(rt);
return;
}
4.延迟更新函数
void down(int rt)
{
int m=c[rt].r-c[rt].l+1; //m为该区间段的点数
if(c[rt].add) //该区间段是否已被延迟更新,如果没有则退出,否则更新子节点
{
c[rt<<1].add+=c[rt].add; //更新左儿子节点的add值
c[rt<<1|1].add+=c[rt].add;
c[rt<<1].sum+=(m-(m>>1))*c[rt].add; //更新左儿子节点的sum值
c[rt<<1|1].sum+=(m>>1)*c[rt].add;
c[rt].add=0; //将该区间段标记为已更新
}
}
问:m是干嘛的?赵巨巨:比如我更新到1-2,那么1-2是由两个点组成的即m=2,那么这一段的数值就是m*c[rt].add;add就是记录延迟了几次的标记,比如我延迟了两次1-2那么,我计算值的时候就是 sum=延迟数*点数
(赵巨巨:小意思
)
5.更新函数void update(int rt,int l,int r)
{
if(l<=c[rt].l&&c[rt].r<=r)
{
c[rt].sum+=c[rt].r-c[rt].l+1;
c[rt].add++;
return;
}
down(rt); //将区间段进行延迟操作
int mid=(c[rt].l+c[rt].r)>>1;
if(l<=mid)
update(rt<<1,l,r);
if(mid<r)
update(rt<<1|1,l,r);
up(rt);
return;
}
6.查询函数int query(int rt,int l,int r)
{
if(l<=c[rt].l&&c[rt].r<=r)
{
return c[rt].sum;
}
down(rt); //将区间段进行延迟操作
int mid=(c[rt].l+c[rt].r)>>1;
int le=0,re=0;
if(l<=mid)
le=query(rt<<1,l,r);
if(mid<r)
re=query(rt<<1|1,l,r);
return le+re;
}
完整代码:#include<stdio.h>
#define MAX 100000
struct Node{
int add;
int sum;
int l;
int r;
}c[MAX*3];
void down(int rt)
{
int m=c[rt].r-c[rt].l+1;
if(c[rt].add)
{
c[rt<<1].add+=c[rt].add;
c[rt<<1|1].add+=c[rt].add;
c[rt<<1].sum+=(m-(m>>1))*c[rt].add;
c[rt<<1|1].sum+=(m>>1)*c[rt].add;
c[rt].add=0;
}
}
void up(int rt)
{
c[rt].sum=c[rt<<1].sum+c[rt<<1|1].sum;
}
void create(int rt,int l,int r)
{
c[rt].l=l;
c[rt].r=r;
c[rt].add=0;
if(c[rt].l==c[rt].r)
{
c[rt].sum=0;
return;
}
int mid=(l+r)>>1;
create(rt<<1,l,mid);
create(rt<<1|1,mid+1,r);
up(rt);
return;
}
void update(int rt,int l,int r)
{
if(l<=c[rt].l&&c[rt].r<=r)
{
c[rt].sum+=c[rt].r-c[rt].l+1;
c[rt].add++;
return;
}
down(rt);
int mid=(c[rt].l+c[rt].r)>>1;
if(l<=mid)
update(rt<<1,l,r);
if(mid<r)
update(rt<<1|1,l,r);
up(rt);
return;
}
int query(int rt,int l,int r)
{
if(l<=c[rt].l&&c[rt].r<=r)
{
return c[rt].sum;
}
down(rt);
int mid=(c[rt].l+c[rt].r)>>1;
int le=0,re=0;
if(l<=mid)
le=query(rt<<1,l,r);
if(mid<r)
re=query(rt<<1|1,l,r);
return le+re;
}
int main()
{
int n,i;
int l,r;
while(scanf("%d",&n),n)
{
create(1,1,n);
for(i=1;i<=n;i++)
{
scanf("%d%d",&l,&r);
update(1,l,r);
}
for(i=1;i<=n;i++)
{
int num;
num=query(1,i,i);
if(i!=1)
printf(" ");
printf("%d",num);
}
printf("\n");
}
return 0;
}
相关文章推荐
- HDOJ 1556 Color the ball 线段树 : 成段更新 单点查询
- HDOJ 1556 Color the ball(线段树 + 线状数组)
- hdoj 1556 Color the ball【线段树区间更新】
- hdoj 1556 Color the ball 【线段树 + lazy区间更新】 【树状数组】
- HDOJ1556 Color the ball 【线段树】+【树状数组】+【标记法】
- HDOJ 1556 Color the ball (线段树+区间更新)
- HDU 1556 Color the ball 线段树入门题
- hdu 1556 Color the ball (树状数组||线段树成段更新)
- hdoj 1556 Color the ball(线段树||树状数组)
- HDOJ 1556 Color the ball(树状数组 & 线段树)
- hdoj 1556 Color the ball 【线段树】
- HDU1556-Color the ball-线段树成段更新入门题/前缀和
- Color the ball----HDOJ1556
- hdu 1556 Color the ball (线段树之扫描线)
- hdu 1556 Color the ball(线段树区间更新单点查询+懒惰标记)
- hdoj--1556--Color the ball(模拟&&树状数组)
- HDOJ 1556 Color the ball
- 【HDOJ】1556 Color the ball
- Color the ball HDOJ--1556
- hdu 1556 Color the ball(线段树)