您的位置:首页 > 其它

模板:线段树(2)区间修改

2016-03-16 20:21 477 查看
好像叫做懒操作来着。。还是叫延迟修改更高大上一点吧

增加操作

//区间修改

/*两种操作
Add(L ,R ,v):把A[L],A[L+1],...,A[R]的值全部增加v
Query(L ,R )计算子序列A[L],A[L+1],...,A[R]的元素和,最小值和最大值
*/

//修改/查询的范围均为[y1,y2]

//维护节点o,它对应区间[L,R]
void maintain(int o, int l, int r) {
int lc = o*2, rc = o*2+1;
if(r > l) { //考虑左右子树
sumv[o] = sumv[lc] + sumv[rc];
minv[o] = min(minv[lc], minv[rc]);
maxv[o] = max(maxv[lc], maxv[rc]);
}
minv[o] += addv[o];
maxv[o] += addv[o];
sumv[o] += addv[o] * (r-l+1);//考虑add操作
if(r==l) addv[o] = 0;
}

void update(int o, int l, int r) {
int lc = o*2, rc = o*2+1;
if(y1 <= l && r <= y2) { //递归边界
addv[o] += v;        //累加边界的add值
}
else {
int m = l + (r-l)/2;
if(y1 <= m) update(lc, l, m);
if(y2 > m) update(rc, m+1, r);
}
maintain(o, l, r);  //递归结束前重新计算本节点的附加信息
}

int _min, _max, _sum;   //全局变量,目前位置的最小值、最大值和累加值

void query(int o, int l, int r,int add){  //add为当前节点延迟修改值
if(y1 <= l && y2 >= r) {  //递归边界:用边界区间的附加信息更新答案
_sum += sumv[o] + add * (r-l+1);
_min = min(_min, minv[o] + add);
_max = max(_max, maxv[o] + add);
}
else {  //递归统计,累加参数add
int m = l + (r-l)/2;
if(y1 <= m) query(o*2, l, m, add + addv[o]);
if(y2 > m) query(o*2+1, m+1, r, add + addv[o]);
}
}


设置操作

/*两种操作:
Set(l, r, v): 把A[l],A[l+1],,...,A[r]的值全部修改为v(v>=0)
Query(l, r): 计算子序列A[l],A[l+1],...,A[r]的元素和、最小值和最大值
*/

void update(int o, int l, int r) {
int lc = o*2, rc = o*2+1;
if(y1 <= l && y2 >= r) { //标记修改
setv[o] = v;
}
else {
pushdown(o);
int m = l + (r-l)/2;
if(y1 <= m) update(lc, l, m); else maintain(lc, l, m);
if(y2 > m) update(rc, m+1, r); else maintain(rc, m+1, r);
}
maintain(o, l, r);
}

//标记传递
void pushdown(int o){
int lc = o*2, rc = o*2+1;
if(setv[o] >= 0) { //本节点有标记才传递。 注意本题中set值非负,所以-1代表没有标记
setv[lc] = setv[rc] = setv[o];
setv[o] = -1; //消除本节点标记
}
}

void query(int o, int l, int r) {
if(setv[o] >= 0) {  //递归边界1: 有set标记
_sum += setv[o] * (min(r, y2)-max(l, y1)+1);
_min = min(_min, setv[o]);
_max = max(_max, setv[o]);
}
else if(y1 <= l && y2 >= r) {  //递归边界2:边界区间
_sum += sumv[o];
_min = min(_min, setv[o]);
_max = max(_max, setv[o]);
}
else {                  //递归统计
int m = l + (r-l)/2;
if(y1 <= m) query(o*2, l, m);
if(y2 > m) query(o*2+1, m+1, r);
}
}


上面set操作的maintain貌似需要重写一下,等我找一道题目试一下再修改。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: