HDU 1698 Just a Hook (线段树区间修改)
题目链接:HDU 1698 Just a Hook
【题目大意】
在Dota里面有个角色叫屠夫,他的武器是 Meat Hook,对所有的英雄都有着致命的威胁, Meat Hook 由一系列连续金属构成(假设有N块金属),金属有 铜 ,银 ,金 三种,分别对应价值 1 2 3。
开始的时候 Meat Hook 都是由 铜 构成,(也就是每一节金属价值都是 1,总价值为N*1),现在我们给出一些操作,让给定区间的 Meat Hook 改变金属等级 ,求出最终整个 Meat Hook的价值;
【样例输入】
1 //1组数据 10 // 10块金属 2 //2组操作 1 5 2 //1 到 5块金属的价值全部变成2 5 9 3 //5 到 3块金属的价值全部变成3
【样例输出】
Case 1: The total value of the hook is 24.
第一次没看模板敲出来的线段树区间修改,贴个代码;
sum记录子节点的和,
val记录当前节点的值 ,看了下以前敲定模板, 也可以不用val ,直接在setv中储存也行;
熟悉了pushdown的写法
【源代码】
#include <iostream> #include <cstdio> #define L(m) m<<1 #define R(m) m<<1|1 using namespace std; const int maxn =100000+10; struct node{ int l,r,sum,val; int setv; //懒惰标记 }tree[maxn<<2]; void pushup(int m){ tree[m].sum = tree[L(m)].sum + tree[R(m)].sum; tree[m].val = tree[L(m)].val; } void pushdown(int m){ if(tree[m].setv){ tree[L(m)].val = tree[R(m)].val = tree[m].val; tree[L(m)].sum = (tree[L(m)].r-tree[L(m)].l+1)*tree[m].val; //这句不要漏了, 子节点的和也要在这里更新 tree[R(m)].sum = (tree[R(m)].r-tree[R(m)].l+1)*tree[m].val; tree[L(m)].setv = tree[R(m)].setv = 1; tree[m].setv = 0; } } void Update(int m,int l,int r,int x){ if(tree[m].l >=l && tree[m].r <=r){ tree[m].setv = 1; tree[m].val = x; tree[m].sum = (tree[m].r - tree[m].l + 1) *x; return ; } pushdown(m); int mid = (tree[m].l + tree[m].r)>>1; //注意这里 if(mid>=r) Update(L(m),l,r,x); else if(mid<l) Update(R(m),l,r,x); else{ Update(L(m),l,mid,x); Update(R(m),mid+1,r,x); } pushup(m); //回溯 } void Build(int m,int l,int r){ tree[m].l = l,tree[m].r = r; if(l == r){ tree[m].setv=0; //初始化 tree[m].sum=1; tree[m].val=1; return ; } int mid = (l + r)>>1; Build(L(m),l,mid); Build(R(m),mid+1,r); pushup(m); } int main(){ int T,n,p; scanf("%d",&T); for(int i=1;i<=T;i++){ scanf("%d%d",&n,&p); Build(1,1,n); int a,b,c; while(p--){ scanf("%d%d%d",&a,&b,&c); Update(1,a,b,c); } printf("Case %d: The total value of the hook is %d.\n",i,tree[1].sum); //以为求得是全部的和,所以直接输出根节点的sum } return 0; }