[HDOJ 1556] Color the ball(线段树成段更新入门)

来源:互联网 发布:java 调用ant 编辑:程序博客网 时间:2024/06/05 14:06

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1556


类型:线段树

由于本人比较懒,所以就不对线段树进行具体介绍了,想了解的走向传送门:http://wenku.baidu.com/view/addd85ab84868762caaed5cd.html

什么?你看了之后还不知道什么是线段树?那就快召唤赵巨巨,赵巨巨acm领军品牌!
(赵巨巨:嘿嘿,线段树俺早就会了,你们都太弱了)

题目大意:
输入一个数n,接下来有n组数据,每组数据代表一个区间段,输入完第n组数据后你需要输出每个点的被覆盖次数。

题解:
以下以介绍成段更新为主

所谓成段更新,简单的说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新或者询问到的时候再传递下去。延迟标记的意思是:这个区间的左右儿子都需要被更新,但是当前区间已经更新了。

算法过程: 
每次更新并不需要更新到叶节点; 
只需更新到相应的段就可以了,然后记录个add; 
下次更新或者查询的时候,如果要查到该段的子节点; 
就把add加到子节点上去,再将该add设为0; 
这样查询子区间的复杂度就是更新的复杂度; 

(赵巨巨:[HDOJ 1556] Color the ball(线段树成段更新入门) - CodeTank - CodeTank的博客

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=延迟数*点数

(赵巨巨:小意思[HDOJ 1556] Color the ball(线段树成段更新入门) - CodeTank - CodeTank的博客
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;
}



0 0
原创粉丝点击