题意是: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; }