hdu 1698 Just a Hook

题意是:dota中屠夫的钩子,分为n段,每一段刚开始的时候价值为1,他可以对自己的钩子进行改造,改造过程中可以把钩子换成价值2,价值3或价值1的钩子。每次更新一个区间上的钩子,即x-y之间的钩子进行改造。问经过m次改造,钩子的总价值。

此题是明显的线段树题目,而且是更新段数据的线段树。这种线段树的难点是延迟标记,理解了这点就好做了。线段树的延迟标记很好,标记之后只有在用到某段的时候才会进行更新,如果没用到某段,则一直被标记。 线段树是很强大的数据结构!

#include <cstdio>
#include <iostream>

using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int maxx=100002;

int sum[maxx<<2];
int col[maxx<<2];

void build(int l,int r,int rt){
	sum[rt]=1;
	col[rt]=0; //这里就是对rt为根节点的段进行延迟标记
	if(l==r)return ;
	int m=(l+r)>>1;
	build(lson);
	build(rson);
	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

void pushDown(int rt,int m){ //更新ret为根的线段树的下一层节点,但不更新到底
	if(col[rt]){
		col[rt<<1]=col[rt<<1|1]=col[rt];//将标记继续延迟到孩子区间
		sum[rt<<1]=(m-(m>>1))*col[rt];//m是以rt为根节点的左右孩子区间的总长度,其中左半区间的长度为m-(m/2)
		sum[rt<<1|1]=(m>>1)*col[rt]; //右半孩子的长度为m/2取整
		col[rt]=0;// 将rt的延迟标记执行之后就将其延迟标记置为0,将延迟推到下一层,本层取消
	}
}

void update(int L,int R,int c,int l,int r,int rt){
	if(L<=l && r<=R){
		sum[rt]=c*(r-l+1);
		col[rt]=c;
		return ;
	}
	pushDown(rt,r-l+1);//这里一定要向下更新线段树
	int m=(r+l)>>1;
    if(L<=m)update(L,R,c,lson);//更新线段树中相应层的根节点的左孩子区间
	if(R>m) update(L,R,c,rson);//更新线段树中相应层的根节点的右孩子区间
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

int main(){
	int cas,n,m;
	scanf("%d",&cas);
	for(int i=1;i<=cas;i++){
		scanf("%d",&n);
		build(1,n,1);
		scanf("%d",&m);
		int x,y,cl;
		while(m--){
			scanf("%d%d%d",&x,&y,&cl);
			update(x,y,cl,1,n,1);
		}
		printf("Case %d: The total value of the hook is %d.\n",i,sum[1]);
	}
	return 0;
}


你可能感兴趣的:(hdu 1698 Just a Hook)