您的位置:首页 > 其它

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

2017-10-09 19:31 351 查看
题目链接:https://vjudge.net/problem/HDU-1698

题目意思:有T组样例,每组样例给出n个棍子,开始棍子价值都是1,给出q个操作,可以把编号【x,y】之间的棍子的值改为z(z可以是1,2,3),求最终总价值。

分析:线段树区间修改,比较点修改,多了一个addv数组,该数组的意义在于可以记录修改的值。注意理解一个区间内其和为addv[rt]*(l-r+1),意义是改变值与区间长度的乘积,这样区间的和便化为区间内点值得和。区间修改不同于点修改,区间修改会影响许多节点,点修改则只影响其一个节点

代码如下:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
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; i<q; i++) {
int 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]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: