题目链接:Click here~~
题意:
最经典的区间染色入门问题。
初始时区间[1,n]的颜色都是1,之后有若干操作,改变某段区间的颜色,输出最后区间[1,n]的颜色之和。
解题思路:
主要说如何做lazy标记。
就是更新时,不更新到最底层(那样太浪费时间)。
对每一个节点,用一个标记记录这段区间是否是同一段颜色。
更新时,若当前节点正好是需要更新的区间,只要直接对这个节点改变标记即可。
若不是,则说明当前节点的区间大于需要更新的区间,此时如果直接改变标记会将那些不属于更新区间的点也改变了颜色。
做法是:将当前节点的标记传给它的两个儿子,并把自己的标记清空,然后再继续更新它的儿子区间,这样就解决了上面的问题。
而查询时,如果碰到有标记的节点,则可以不用继续递归,直接返回这段区间的颜色之和。
如果没有标记,则需要访问它的两个儿子,才能知道这段区间的颜色之和。
#include <stdio.h>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)
typedef __int64 LL;
const int M = 100003;
struct Tnode
{
int l,r;
int color;
}T[M<<2];
void Build(int u,int l,int r)
{
T[u].l = l , T[u].r = r;
if(l == r-1)
{
T[u].color = 1;
return ;
}
int mid = MID(l,r);
Build(L(u),l,mid);
Build(R(u),mid,r);
T[u].color = 0;
}
void Updata(int u,int l,int r,int up)
{
if(T[u].color == up || T[u].l == l && T[u].r == r)
{
T[u].color = up;
return ;
}
if(T[u].color)
{
T[L(u)].color = T[u].color;
T[R(u)].color = T[u].color;
T[u].color = 0;
}
int mid = MID(T[u].l,T[u].r);
if(l >= mid)
Updata(R(u),l,r,up);
else
if(r <= mid)
Updata(L(u),l,r,up);
else
{
Updata(L(u),l,mid,up);
Updata(R(u),mid,r,up);
}
}
int Query(int u,int l,int r)
{
int mid = MID(T[u].l,T[u].r);
if(T[u].l == l && T[u].r == r)
if(T[u].color)
return T[u].color*(r-l);
else
return Query(L(u),l,mid) + Query(R(u),mid,r);
if(l >= mid)
return Query(R(u),l,r);
else
if(r <= mid)
return Query(L(u),l,r);
else
return Query(L(u),l,mid) + Query(R(u),mid,r);
}
int main()
{
//freopen("in.ads","r",stdin);
int n,z,Q,a,b,num;
int ncase = 0;
scanf("%d",&z);
while(z--)
{
scanf("%d%d",&n,&Q);
Build(1,1,n+1);
while(Q--)
{
scanf("%d%d%d",&a,&b,&num);
Updata(1,a,b+1,num);
}
printf("Case %d: The total value of the hook is %d.\n",++ncase,Query(1,1,n+1));
}
return 0;
}