题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1698
题目意思:
有n个棒子,每个棒子都有一个值,q个更新,每次更新时有三个参数x,y,z表示,把x-y区间内的棒子的值改成z,为最后所有棒子的值的总和是多少。
解题思路:
建一个n大小的线段树,用sum[rt]表示该节点区间的值总和,value[rt]表示该区间当前所处的状态,如果为非零则表示该区间内所有棒子为该值,并且没有传下去,如果为零,说明该区间内的状态改变都已传下去了。每次更新完毕后将该区间的sum值求出(向上更新),最后输出sum[1]即可。
关键:更新延迟,不是每次更新都更新到叶子节点,记录状态等下次更新时再往下更新,但每次都把顶层的sum值给求出来。
详见代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF (1<<30)
#define PI acos(-1.0)
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,(rt<<1)|1
#define maxn 110000
int sum[maxn*4],value[maxn*4]; //作为标记如果为非零则表示没有向下传
/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
return ;
}
void build(int l,int r,int rt)
{
value[rt]=0; //不需往下传
sum[rt]=1;//叶子节点,开始均为铜1
if(l==r)
return ;
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
return ;
}
void pushdown(int rt,int num) //向下传,num为该区间点的总的个数
{
if(value[rt])
{
value[rt<<1]=value[rt<<1|1]=value[rt];
sum[rt<<1]=(num-(num>>1))*value[rt]; //注意前一区间可能后一区间多一,所以前一区间可能比后面多一个
sum[rt<<1|1]=(num>>1)*value[rt];
value[rt]=0;//表示该节点以向下更新,下次不必下传了
}
return ;
}
void update(int L,int R,int v,int l,int r,int rt)
{
if(L<=l&&R>=r) //如果要查找的区间包括当前空间,就不往下更新了,保存
{
value[rt]=v;
sum[rt]=v*(r-l+1);
return ;
}
//如果不能包括该区间,说明要分,先将上次的传下去
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
update(L,R,v,lson);//必须更新左边
if(R>m)
update(L,R,v,rson);//必须更新右边
pushup(rt); //向上传
return ;
}
int main()
{
int ca,n,q;
scanf("%d",&ca);
for(int k=1;k<=ca;k++)
{
scanf("%d%d",&n,&q);
build(1,n,1);
while(q--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
update(a,b,c,1,n,1);
}
printf("Case %d: The total value of the hook is %d.\n",k,sum[1]);
}
return 0;
}