线段树模板(区间修改)——hdu1698

题目链接:https://vjudge.net/problem/HDU-1698
题目意思:有T组样例,每组样例给出n个棍子,开始棍子价值都是1,给出q个操作,可以把编号【x,y】之间的棍子的值改为z(z可以是1,2,3),求最终总价值。
分析:线段树区间修改,比较点修改,多了一个addv数组,该数组的意义在于可以记录修改的值。注意理解一个区间内其和为addv[rt]*(l-r+1),意义是改变值与区间长度的乘积,这样区间的和便化为区间内点值得和。区间修改不同于点修改,区间修改会影响许多节点,点修改则只影响其一个节点
代码如下:

#include 
#include
#include
#include
using namespace std;
const int maxn=100000+5;
int addv[maxn<<2];
int sum[maxn<<2];
//改变[l,r]区间内其子节点的addv值和sum值
void pushdown(int rt,int l,int r) {
    int m=(l+r)>>1;
    if(addv[rt]) {                        //本节点需要被标记才能箱子传递
        addv[rt<<1]=addv[rt<<1|1]=addv[rt];  //子节点区间和父节点addv值相同
        sum[rt<<1]=addv[rt<<1]*(m-l+1);//sum值=addv值*区间长度
        sum[rt<<1|1]=addv[rt<<1|1]*(r-m);
        addv[rt]=0;                       //取消标记
    }
}
//建树
void build(int l,int r,int rt) {
    addv[rt]=0;        //比点修改多了一处
    if(l==r) {         //叶节点赋值
        sum[rt]=1;
        return ;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);   //向左走
    build(m+1,r,rt<<1|1);//向右走
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];//更新sum值
}
//更新区间值
void update(int ll,int rr,int c,int l,int r,int rt) {
    if(ll<=l&&rr>=r) {             //叶节点直接更新
        addv[rt]=c;
        sum[rt]=addv[rt]*(r-l+1);
        return ;
    }
    pushdown(rt,l,r);            //需要向下传递
    int m=(l+r)>>1;
    if(ll<=m)update(ll,rr,c,l,m,rt<<1);
    if(rr>m)update(ll,rr,c,m+1,r,rt<<1|1);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
//查询,和点修改类似
int query(int ll,int rr,int l,int r,int rt) {
    if(ll<=l&&rr>=r) {
        return sum[rt];
    }
    int m=(l+r)>>1;
    int res=0;
    if(ll<=m)res+=query(ll,rr,l,m,rt<<1);
    if(rr>m)res+=query(ll,rr,m+1,r,rt<<1|1);
    return res;
}
int main() {
    int T;
    scanf("%d",&T);
    int kase=0;
    while(T--) {
        int n,q;
        scanf("%d%d",&n,&q);
        build(1,n,1);
        for(int i=0; iint x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            update(x,y,z,1,n,1);
        }
        printf("Case %d: The total value of the hook is %d.\n",++kase,sum[1]);
    }
}

你可能感兴趣的:(数据结构————线段树)