add无序,set有序。规定同时有两个标记时,表示先执行set再执行add。

1. 更新操作:

 int op,cl,cr,v;
void update(int o, int L, int R) {
int lc = o*, rc = o*+;
if(cl <= L && cr >= R) { // 标记修改
if(op == ) addv[o] += v;
else { setv[o] = v; addv[o] = ; }
} else {
pushdown(o);
int M = L + (R-L)/;
if(cl <= M) update(lc, L, M); else maintain(lc, L, M);
if(cr > M) update(rc, M+, R); else maintain(rc, M+, R);
}
maintain(o, L, R);
}

此操作中需要维护标记,这里保证了不会出现先有add再有set,这种情况只会保留set。

值得注意的是,标记下推时左右子树都需要维护,其中递归进入的子树会在递归结束时自然调用maintain函数,而另一个子树需要手动调用maintain。

2. 标记传递:

 void pushdown(int o) {
int lc = o*, rc = o*+;
if(setv[o] >= ) {
setv[lc] = setv[rc] = setv[o];
addv[lc] = addv[rc] = ;
setv[o] = -; // 清除本结点标记
}
if(addv[o]) {
addv[lc] += addv[o];
addv[rc] += addv[o];
addv[o] = ; // 清除本结点标记
}
}

set和add分别讨论,结点o有标记时才下推。

3. 维护信息:

 void maintain(int o, int L, int R) {
int lc = o*, rc = o*+;
if(R > L) {
sumv[o] = sumv[lc] + sumv[rc];
minv[o] = min(minv[lc], minv[rc]);
maxv[o] = max(maxv[lc], maxv[rc]);
}
if(setv[o] >= ) { minv[o] = maxv[o] = setv[o]; sumv[o] = setv[o] * (R-L+); }
if(addv[o]) { minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (R-L+); }
}

注意:所有叶子上总是保留set标记(初始化的)而不会被清除(pushdown只能针对非叶结点),因此maintain函数对于叶子来说并不会重复累加addv[o].

4. 查询信息:

 int ql, qr;
void query(int o, int L, int R, int& ssum, int& smin, int &smax) {
int lc = o*, rc = o*+;
maintain(o, L, R); // 处理被pushdown下来的标记
if(ql <= L && qr >= R) {
ssum = sumv[o];
smin = minv[o];
smax = maxv[o];
} else {
pushdown(o);
int M = L + (R-L)/;
int lsum = , lmin = INF, lmax = -INF;
int rsum = , rmin = INF, rmax = -INF;
if(ql <= M) query(lc, L, M, lsum, lmin, lmax); else maintain(lc, L, M);
if(qr > M) query(rc, M+, R, rsum, rmin, rmax); else maintain(rc, M+, R);
ssum = lsum + rsum;
smin = min(lmin, rmin);
smax = max(lmax, rmax);
}
}

也要维护信息和下推标记。

5. 初始化:

通过add,当然,也可以通过set.

 memset(setv, , sizeof(setv));   //保证叶子结点的set标签
for(int i = ; i <= n;i++)
{
scanf("%d", &v);
cl = cr = i; v = a[i]; op=;
update(, , n);
}
 #include<bits/stdc++.h>
using namespace std; const int INF = 0x3f3f3f3f;
const int maxn = + ;
const int maxnode = maxn << ;
int sumv[maxnode], minv[maxnode], maxv[maxnode], setv[maxnode], addv[maxnode];
int n, a[maxn]; // 维护信息
void maintain(int o, int L, int R) {
int lc = o*, rc = o*+;
if(R > L) {
sumv[o] = sumv[lc] + sumv[rc];
minv[o] = min(minv[lc], minv[rc]);
maxv[o] = max(maxv[lc], maxv[rc]);
}
if(setv[o] >= ) { minv[o] = maxv[o] = setv[o]; sumv[o] = setv[o] * (R-L+); }
if(addv[o]) { minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (R-L+); }
} // 标记传递
void pushdown(int o) {
int lc = o*, rc = o*+;
if(setv[o] >= ) {
setv[lc] = setv[rc] = setv[o];
addv[lc] = addv[rc] = ;
setv[o] = -; // 清除本结点标记
}
if(addv[o]) {
addv[lc] += addv[o];
addv[rc] += addv[o];
addv[o] = ; // 清除本结点标记
}
} int op,cl,cr,v;
void update(int o, int L, int R) {
int lc = o*, rc = o*+;
if(cl <= L && cr >= R) { // 标记修改
if(op == ) addv[o] += v;
else { setv[o] = v; addv[o] = ; }
} else {
pushdown(o);
int M = L + (R-L)/;
if(cl <= M) update(lc, L, M); else maintain(lc, L, M);
if(cr > M) update(rc, M+, R); else maintain(rc, M+, R);
}
maintain(o, L, R);
} int ql, qr;
void query(int o, int L, int R, int& ssum, int& smin, int &smax) {
int lc = o*, rc = o*+;
maintain(o, L, R); // 处理被pushdown下来的标记
if(ql <= L && qr >= R) {
ssum = sumv[o];
smin = minv[o];
smax = maxv[o];
} else {
pushdown(o);
int M = L + (R-L)/;
int lsum = , lmin = INF, lmax = -INF;
int rsum = , rmin = INF, rmax = -INF;
if(ql <= M) query(lc, L, M, lsum, lmin, lmax); else maintain(lc, L, M);
if(qr > M) query(rc, M+, R, rsum, rmin, rmax); else maintain(rc, M+, R);
ssum = lsum + rsum;
smin = min(lmin, rmin);
smax = max(lmax, rmax);
}
} void print_debug(int o, int L, int R)
{
printf("o:%d L:%d R:%d setv:%d addv:%d minv:%d\n", o, L, R, setv[o], addv[o], minv[o]);
if(R > L)
{
int M = L + (R - L) / ;
print_debug(*o, L, M);
print_debug(*o+, M+, R);
}
} int main()
{
memset(setv, , sizeof(setv)); printf("数组元素个数:");
scanf("%d", &n);
printf("数组元素:");
for(int i = ; i <= n;i++)
{
scanf("%d", &a[i]);
cl = cr = i; v = a[i]; op=;
update(, , n);
} printf("1代表查询,2代表增加,3代表设置\n");
printf("选择:");
int chose;
while(scanf("%d", &chose) == )
{
if(chose == )
{
printf("查询的左右区间:");
scanf("%d%d", &ql, &qr);
int ssum, smin, smax;
query(, , n, ssum, smin, smax);
printf("最小值:%d\n", smin);
print_debug(, , n);
}
else if(chose == )
{
printf("左右区间和增加值:");
scanf("%d%d%d", &cl, &cr, &v);
op = ;
update(, , n);
print_debug(, , n);
}
else
{
printf("左右区间和设置值:");
scanf("%d%d%d", &cl, &cr, &v);
op = ;
update(, , n);
print_debug(, , n);
}
printf("选择:");
} return ;
}

完整代码

线段树(四)——两个标记(add和set)的更多相关文章

  1. CodeForces Round #179 (295A) - Greg and Array 一个线段树做两次用

    线段树的区间更新与区间求和...一颗这样的线段树用两次... 先扫描1~k...用线段树统计出每个操作执行的次数... 那么每个操作就变成了 op. l  , op.r , op.c= times* ...

  2. [HDOJ4578]Transformation(线段树,多延迟标记)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所 ...

  3. 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化

    4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 247  Solved: 113[Submit][Status][Discuss ...

  4. 【HDU 4614】Vases and Flowers(线段树区间更新懒惰标记)

    题目0到n-1的花瓶,操作1在下标a开始插b朵花,输出始末下标.操作2清空[a,b]的花瓶,求清除的花的数量.线段树懒惰标记来更新区间.操作1,先查询0到a-1有num个空瓶子,然后用线段树的性质,或 ...

  5. 扶桑号战列舰 (单调栈+线段树区间更新懒惰标记 or 栈)

    传送门 •题目描述 题目描述 众所周知,一战过后,在世界列强建造超无畏级战列舰的竞争之中,旧日本海军根据“个舰优越主义”,建造了扶桑级战列舰,完工时为当时世界上武装最为强大的舰只. 同时,扶桑号战列舰 ...

  6. HDU 4553 约会安排(线段树区间合并+双重标记)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 题目大意:就是有三种操作: ①DS x,安排一段长度为x的空闲时间跟屌丝一起,输出这段时间的起点 ...

  7. HDU 3911 Black And White (线段树区间合并 + lazy标记)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3911 给你n个数0和1,m个操作: 0操作  输出l到r之间最长的连续1的个数 1操作  将l到r之间 ...

  8. 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)

    欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memor ...

  9. 【codevs2216】行星序列 线段树 区间两异同修改+区间求和*****

    [codevs2216]行星序列 2014年2月22日3501 题目描述 Description “神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小 ...

  10. FZU-1608 Huge Mission 线段树(更新懒惰标记)

    题目链接: https://cn.vjudge.net/problem/FZU-1608 题目大意: 长度n,m次操作:每次操作都有三个数:a,b,c:意味着(a,b]区间单位长度的价值为c,若某段长 ...

随机推荐

  1. [转帖] 飞腾FT2000+ CPU的进展(2019.6)

    中国长城:拟进一步收购飞腾股权,强化信息基础设施国产化平台地位 2019-06-26 09:28 http://www.sohu.com/a/323065095_100016383 今年年中的事情 浪 ...

  2. 解决redis运行期间key值过期但是内存memory依然占用过高

    要解决这个问题,首先要了解redis info信息中几个数据的意义:   used_memory:810575104 //数据占用了多少内存(字节)  used_memory_human:773.02 ...

  3. SQL SERVER修改字段为首字母大写

    --修改字段为首字母大写 -- EXEC sp_rename 'ShenBao_CaiGouFuKuan.Tid', 'Tid', @objtype = 'COLUMN'; SELECT 'EXEC ...

  4. ubuntu18上传代码到github

    其实在github上建仓库时候就提示你步骤了: 1.注册个github账号并登录 创建一个仓库 https://github.com/ 2.创建SSH Key ssh-keygen -t rsa -C ...

  5. LC 202. Happy Number

    问题描述 Write an algorithm to determine if a number is "happy". A happy number is a number de ...

  6. 考研路茫茫——空调教室HDU2242(Tarjan缩点)

    题意:http://acm.hdu.edu.cn/showproblem.php?pid=2242 给你一个图,问你缩完点树上割边的做小绝对值差. 思路: 这题核算起来整整做了我一天(即24个小时)! ...

  7. php 栈、 出栈、入栈

    最近在面试的时候被问到栈,回来做个总结,希望对大家有帮助 栈是线性表的一种,他的特点是后入先出,可以这么理解,栈就像一个存东西的盒子,先放进去的在最底层,后放进去的在上层,因为上层的东西把底层的东西压 ...

  8. 【hash】Seek the Name, Seek the Fame

    [哈希和哈希表]Seek the Name, Seek the Fame 题目描述 The little cat is so famous, that many couples tramp over ...

  9. Web API 自动生成接口文档

    1.添加NuGet程序包 Microsoft ASP.NET Web API 2.2 Help Page      (这是微软官方的) A Simple Test Client for ASP.NET ...

  10. 使用css让表头固定的方法

    1.可以使用display: table; width: 100%; table-layout: fixed; table-layout: fixed;设置表格布局算法.tableLayout 属性用 ...