线段树(四)——两个标记(add和set)
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)的更多相关文章
- CodeForces Round #179 (295A) - Greg and Array 一个线段树做两次用
线段树的区间更新与区间求和...一颗这样的线段树用两次... 先扫描1~k...用线段树统计出每个操作执行的次数... 那么每个操作就变成了 op. l , op.r , op.c= times* ...
- [HDOJ4578]Transformation(线段树,多延迟标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所 ...
- 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化
4636: 蒟蒻的数列 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 247 Solved: 113[Submit][Status][Discuss ...
- 【HDU 4614】Vases and Flowers(线段树区间更新懒惰标记)
题目0到n-1的花瓶,操作1在下标a开始插b朵花,输出始末下标.操作2清空[a,b]的花瓶,求清除的花的数量.线段树懒惰标记来更新区间.操作1,先查询0到a-1有num个空瓶子,然后用线段树的性质,或 ...
- 扶桑号战列舰 (单调栈+线段树区间更新懒惰标记 or 栈)
传送门 •题目描述 题目描述 众所周知,一战过后,在世界列强建造超无畏级战列舰的竞争之中,旧日本海军根据“个舰优越主义”,建造了扶桑级战列舰,完工时为当时世界上武装最为强大的舰只. 同时,扶桑号战列舰 ...
- HDU 4553 约会安排(线段树区间合并+双重标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 题目大意:就是有三种操作: ①DS x,安排一段长度为x的空闲时间跟屌丝一起,输出这段时间的起点 ...
- 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之间 ...
- 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)
欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others) Memor ...
- 【codevs2216】行星序列 线段树 区间两异同修改+区间求和*****
[codevs2216]行星序列 2014年2月22日3501 题目描述 Description “神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小 ...
- FZU-1608 Huge Mission 线段树(更新懒惰标记)
题目链接: https://cn.vjudge.net/problem/FZU-1608 题目大意: 长度n,m次操作:每次操作都有三个数:a,b,c:意味着(a,b]区间单位长度的价值为c,若某段长 ...
随机推荐
- storm manual drpc 的远程调用
一.创建server端 public class ManualDRPC { private static final Logger LOG = LoggerFactory.getLogger(Manu ...
- 浅谈>/dev/null 2>&1
在crond计划任务.nohup中我们经常可以看到>/dev/null 2>&1,但是很多人并不理解其含义,想要真正的理解它,首先我们需要知道文件描述符的三种类型. 类型 文件描述 ...
- html中'disabled'与'readonly'的区别
html中'disabled'与'readonly'的区别 此随笔增量编辑 disabled 在提交表单的时候 值不会带入表单中, 而readonly则可以将值带入表单中.
- 【AtCoder】AGC003
AGC编号越小越水???? AGC003 A - Wanna go back home 相对方向要么一起有要么一起没有 #include <bits/stdc++.h> #define f ...
- 剑指offer46:圆圈中最后剩下的数字(链表,递归)
1 题目描述 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随 ...
- Photon Server 实现注册与登录(四) --- 服务端响应登陆和注册
前面已经整理过了服务端代码,MyGameServer.cs 和 ClientPeer.cs 对请求和响应进行了拆分.接下来处理对前端的响应 一.响应登陆请求 之前整理中,响应前端请求主要在类Clien ...
- T100——汇总错误消息显示
初始化 CALL cl_err_collect_init() 汇总消息显示 CALL cl_err_collect_show()
- Prometheus Operator 自动发现和持久化
Prometheus Operator 自动发现和持久化 之前在 Prometheus Operator 下面自定义一个监控选项,以及自定义报警规则的使用.那么我们还能够直接使用前面课程中的自动发现功 ...
- 训练技巧详解【含有部分代码】Bag of Tricks for Image Classification with Convolutional Neural Networks
训练技巧详解[含有部分代码]Bag of Tricks for Image Classification with Convolutional Neural Networks 置顶 2018-12-1 ...
- 关于vue项目的文件组织
最近参与了好几个项目,都是以vue-cli脚手架生成的项目,参与完成之后,有点关于项目文件组织的看法,很想聊聊. 关于目录 由vue-cli脚手架生成的项目,都会生成一个基本的目录格式. 类似于这种, ...