题意:

已知\(n\)个数字,进行以下操作:

  • \(1.\)给一个区间\([L,R]\) 加上一个数\(x\)
  • \(2.\)把一个区间\([L,R]\) 里小于\(x\) 的数变成\(x\)
  • \(3.\)把一个区间\([L,R]\) 里大于\(x\) 的数变成\(x\)
  • \(4.\)求区间\([L,R]\)的和
  • \(5.\)求区间\([L,R]\)的最大值
  • \(6.\)求区间\([L,R]\) 的最小值

思路:

吉司机线段树。

假如我们要进行把一个区间\([L,R]\) 里小于\(x\) 的数变成\(x\)。那么我们可以维护一个最小值\(Min\)和次小值\(sMin\)和最小值数量\(Minlen\)。那么,当\(Min\geq x\)时,显然这个区间不需要操作;当\(Min<x\)且\(sMin>x\)时,这时只要更新\(Min=x\);当\(sMin\leq x\)时,继续往下\(dfs\)。操作\(3\)也是同理。

因为这里是没设重置的标记的,所以在\(pushdown\)时如果子节点和父节点产生冲突,那么以父节点为准。

复杂度\(O(mlog^2n)\),\(m\)为操作数。

有点卡常。

代码:

#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int maxn = 5e5 + 5;
const int MAXM = 3e6;
const ll MOD = 998244353;
const ull seed = 131;
const int INF = 1 << 30; #define lson (rt << 1)
#define rson (rt << 1 | 1)
int a[maxn];
int Max[maxn << 2], Min[maxn << 2], sMax[maxn << 2], sMin[maxn << 2];
int Maxlen[maxn << 2], Minlen[maxn << 2];
ll sum[maxn << 2];
int lazy[maxn << 2];
inline void pushup(int rt){ //这边建议加上inline
sum[rt] = sum[lson] + sum[rson]; if(Max[lson] < Max[rson]){
Max[rt] = Max[rson];
Maxlen[rt] = Maxlen[rson];
sMax[rt] = max(sMax[rson], Max[lson]);
}
if(Max[lson] > Max[rson]){
Max[rt] = Max[lson];
Maxlen[rt] = Maxlen[lson];
sMax[rt] = max(sMax[lson], Max[rson]);
}
if(Max[lson] == Max[rson]){
Max[rt] = Max[lson];
Maxlen[rt] = Maxlen[lson] + Maxlen[rson];
sMax[rt] = max(sMax[lson], sMax[rson]);
} if(Min[lson] > Min[rson]){
Min[rt] = Min[rson];
Minlen[rt] = Minlen[rson];
sMin[rt] = min(sMin[rson], Min[lson]);
}
if(Min[lson] < Min[rson]){
Min[rt] = Min[lson];
Minlen[rt] = Minlen[lson];
sMin[rt] = min(sMin[lson], Min[rson]);
}
if(Min[lson] == Min[rson]){
Min[rt] = Min[lson];
Minlen[rt] = Minlen[lson] + Minlen[rson];
sMin[rt] = min(sMin[lson], sMin[rson]);
}
}
inline void pushdown(int rt, int l, int r){
int m = (l + r) >> 1;
if(lazy[rt]){
sum[lson] += 1LL * (m - l + 1) * lazy[rt];
sum[rson] += 1LL * (r - m) * lazy[rt];
Max[lson] += lazy[rt];
Max[rson] += lazy[rt];
sMax[lson] += lazy[rt];
sMax[rson] += lazy[rt];
Min[lson] += lazy[rt];
Min[rson] += lazy[rt];
sMin[lson] += lazy[rt];
sMin[rson] += lazy[rt];
lazy[lson] += lazy[rt];
lazy[rson] += lazy[rt];
lazy[rt] = 0;
}
if(Max[lson] > Max[rt]){ //要和父节点保持一致
if(sMax[lson] == Max[lson]) sMax[lson] = Max[rt];
if(Min[lson] == Max[lson]) Min[lson] = Max[rt];
if(sMin[lson] == Max[lson]) sMin[lson] = Max[rt];
sum[lson] += 1LL * (Max[rt] - Max[lson]) * Maxlen[lson];
Max[lson] = Max[rt];
}
if(Max[rson] > Max[rt]){
if(sMax[rson] == Max[rson]) sMax[rson] = Max[rt];
if(Min[rson] == Max[rson]) Min[rson] = Max[rt];
if(sMin[rson] == Max[rson]) sMin[rson] = Max[rt];
sum[rson] += 1LL * (Max[rt] - Max[rson]) * Maxlen[rson];
Max[rson] = Max[rt];
}
if(Min[lson] < Min[rt]){
if(sMin[lson] == Min[lson]) sMin[lson] = Min[rt];
if(Max[lson] == Min[lson]) Max[lson] = Min[rt];
if(sMax[lson] == Min[lson]) sMax[lson] = Min[rt];
sum[lson] += 1LL * (Min[rt] - Min[lson]) * Minlen[lson];
Min[lson] = Min[rt];
}
if(Min[rson] < Min[rt]){
if(sMin[rson] == Min[rson]) sMin[rson] = Min[rt];
if(Max[rson] == Min[rson]) Max[rson] = Min[rt];
if(sMax[rson] == Min[rson]) sMax[rson] = Min[rt];
sum[rson] += 1LL * (Min[rt] - Min[rson]) * Minlen[rson];
Min[rson] = Min[rt];
}
}
void build(int l, int r, int rt){
lazy[rt] = 0;
if(l == r){
sum[rt] = Max[rt] = Min[rt] = a[l];
sMax[rt] = -INF;
sMin[rt] = INF;
Maxlen[rt] = Minlen[rt] = 1;
return;
}
int m = (l + r) >> 1;
build(l, m, lson);
build(m + 1, r, rson);
pushup(rt);
}
void add(int L, int R, int l, int r, int v, int rt){
if(L <= l && R >= r){
sum[rt] += 1LL * v * (r - l + 1);
Max[rt] += v;
Min[rt] += v;
sMax[rt] += v;
sMin[rt] += v;
lazy[rt] += v;
return;
}
pushdown(rt, l, r);
int m = (l + r) >> 1;
if(L <= m)
add(L, R, l, m, v, lson);
if(R > m)
add(L, R, m + 1, r, v, rson);
pushup(rt);
}
void Less(int L, int R, int l, int r, int v, int rt){
if(Min[rt] >= v) return;
if(L <= l && R >= r && sMin[rt] > v){//>保证Minlen不变
if(Max[rt] == Min[rt]) Max[rt] = v;
if(sMax[rt] == Min[rt]) sMax[rt] = v;
sum[rt] += 1LL * (v - Min[rt]) * Minlen[rt] ;
Min[rt] = v;
return;
}
pushdown(rt, l, r);
int m = (l + r) >> 1;
if(L <= m)
Less(L, R, l, m, v, lson);
if(R > m)
Less(L, R, m + 1, r, v, rson);
pushup(rt);
}
void More(int L, int R, int l, int r, int v, int rt){
if(Max[rt] <= v) return;
if(L <= l && R >= r && sMax[rt] < v){ //<保证Maxlen不变
if(Min[rt] == Max[rt]) Min[rt] = v;
if(sMin[rt] == Max[rt]) sMin[rt] = v;
sum[rt] += 1LL * (v - Max[rt]) * Maxlen[rt];
Max[rt] = v;
return;
}
pushdown(rt, l, r);
int m = (l + r) >> 1;
if(L <= m)
More(L, R, l, m, v, lson);
if(R > m)
More(L, R, m + 1, r, v, rson);
pushup(rt);
}
ll querySum(int L, int R, int l, int r, int rt){
if(L <= l && R >= r){
return sum[rt];
}
pushdown(rt, l, r);
int m = (l + r) >> 1;
ll ret = 0;
if(L <= m)
ret += querySum(L, R, l, m, lson);
if(R > m)
ret += querySum(L, R, m + 1, r, rson);
return ret;
}
int queryMax(int L, int R, int l, int r, int rt){
if(L <= l && R >= r){
return Max[rt];
}
pushdown(rt, l, r);
int m = (l + r) >> 1;
int MAX = -INF;
if(L <= m)
MAX = max(MAX, queryMax(L, R, l, m, lson));
if(R > m)
MAX = max(MAX, queryMax(L, R, m + 1, r, rson));
return MAX;
}
int queryMin(int L, int R, int l, int r, int rt){
if(L <= l && R >= r){
return Min[rt];
}
pushdown(rt, l, r);
int m = (l + r) >> 1;
int MIN = INF;
if(L <= m)
MIN = min(MIN, queryMin(L, R, l, m, lson));
if(R > m)
MIN = min(MIN, queryMin(L, R, m + 1, r, rson));
return MIN;
}
inline bool read(int &num){
char in;
bool IsN=false;
in = getchar();
if(in == EOF) return false;
while(in != '-' && (in < '0' || in > '9')) in = getchar();
if(in == '-'){ IsN = true; num = 0;}
else num = in - '0';
while(in = getchar(),in >= '0' && in <= '9'){
num *= 10, num += in-'0';
}
if(IsN) num = -num;
return true;
} int main(){
int n;
read(n);
for(int i = 1; i <= n; i++) read(a[i]);
build(1, n, 1);
int m;
read(m);
while(m--){
int l, r, x, op;
read(op), read(l), read(r);
if(op <= 3) read(x);
if(op == 1) add(l, r, 1, n, x, 1);
else if(op == 2) Less(l, r, 1, n, x, 1);
else if(op == 3) More(l, r, 1, n, x, 1);
else if(op == 4) printf("%lld\n", querySum(l, r, 1, n, 1));
else if(op == 5) printf("%d\n", queryMax(l, r, 1, n, 1));
else printf("%d\n", queryMin(l, r, 1, n, 1));
}
return 0;
}

bzoj4695 最假女选手(势能线段树/吉司机线段树)题解的更多相关文章

  1. BZOJ4695 最假女选手(势能线段树)

    BZOJ题目传送门 终于体会到初步掌握势能分析思想的重要性了. 一开始看题,感觉套路还是很一般啊qwq.直接在线段树上维护最大值和最小值,每次递归更新的时候,如果不能完全覆盖就暴力递归下去.挺好写的欸 ...

  2. 2018.07.27 bzoj4695: 最假女选手(线段树)

    传送门 线段树好题 支持区间加,区间取min" role="presentation" style="position: relative;"> ...

  3. bzoj4695 最假女选手

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4695 [题解] SegmentTree beats!(见jiry_2论文/营员交流) 考虑只 ...

  4. [BZOJ4695]最假女选手:segment tree beats!

    分析 segment tree beats!模板题. 看了gxz的博客突然发现自己写的mxbt和mnbt两个标记没用诶. 代码 #include <bits/stdc++.h> #defi ...

  5. bzoj 4695 最假女选手 吉利线段树

    最假女选手 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 480  Solved: 118[Submit][Status][Discuss] Desc ...

  6. BZOJ.4695.最假女选手(线段树 Segment tree Beats!)

    题目链接 区间取\(\max,\ \min\)并维护区间和是普通线段树无法处理的. 对于操作二,维护区间最小值\(mn\).最小值个数\(t\).严格次小值\(se\). 当\(mn\geq x\)时 ...

  7. BZOJ4695:最假女选手

    浅谈区间最值操作和历史最值问题:https://www.cnblogs.com/AKMer/p/10225100.html 题目传送门:https://lydsy.com/JudgeOnline/pr ...

  8. bzoj 4695: 最假女选手 && Gorgeous Sequence HDU - 5306 && (bzoj5312 冒险 || 小B的序列) && bzoj4355: Play with sequence

    算导: 核算法 给每种操作一个摊还代价(是手工定义的),给数据结构中某些东西一个“信用”值(不是手动定义的,是被动产生的),摊还代价等于实际代价+信用变化量. 当实际代价小于摊还代价时,增加等于差额的 ...

  9. HDU - 5306 Gorgeous Sequence (吉司机线段树)

    题目链接 吉司机线段树裸题... #include<bits/stdc++.h> using namespace std; typedef long long ll; ,inf=0x3f3 ...

随机推荐

  1. JVM虚拟机基础

    JVM 全称Java Virtual Machine,也就是我们耳熟能详的Java 虚拟机.它能识别.class 后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作. Ja ...

  2. MongoDB 总结

    目录 1. 逻辑结构 2. 安装部署 2.1 系统准备 2.2 mongodb安装 2.2.1 创建所需用户和组 2.2.2 创建mongodb所需目录结构 2.2.3 上传并解压软件到指定位置 2. ...

  3. Redis 核心篇:唯快不破的秘密

    天下武功,无坚不摧,唯快不破! 学习一个技术,通常只接触了零散的技术点,没有在脑海里建立一个完整的知识框架和架构体系,没有系统观.这样会很吃力,而且会出现一看好像自己会,过后就忘记,一脸懵逼. 跟着「 ...

  4. JVM学习-运行时数据区域

    目录 前言 运行时数据区 程序计数器 Java虚拟机栈 局部变量表 基础数据类型 对象引用 returnAddress 操作数栈 动态链接 方法返回地址 Java堆 方法区 类型信息 字段描述符 方法 ...

  5. vercel是什么神仙网站?

    Vercel? vercel是我用过的最好用的网站托管服务.本网站就是基于hexo引擎模板开发,托管在vercel上的. vercel类似于github page,但远比github page强大,速 ...

  6. What is the difference between btree and rtree indexing?

    https://softwareengineering.stackexchange.com/questions/113256/what-is-the-difference-between-btree- ...

  7. 进程通信类型 管道是Linux支持的最初Unix IPC形式之一 命名管道 匿名管道

    管道 Linux环境进程间通信(一) https://www.ibm.com/developerworks/cn/linux/l-ipc/part1/index.html 管道及有名管道 郑彦兴200 ...

  8. DDD领域驱动设计:仓储

    1 前置阅读 在阅读本文章之前,你可以先阅读: 什么是DDD DDD的实体.值对象.聚合根的基类和接口:设计与实现 2 什么是仓储? 仓储封装了基础设施来提供查询和持久化聚合操作. 它们集中提供常见的 ...

  9. 在ubuntu编写helloworld

    安装vim 打开终端 输入sudo apt-get install vim-gtk 输入登陆密码 等待安装完成 编译C 创建.c文件:vim helloworld.c 编写代码,保存并退出 编译:gc ...

  10. Codeforces Round #671 (Div. 2) (A~E)

    Link~ 题面差评,整场都在读题 A 根据奇偶性判断一下即可. #include<bits/stdc++.h> #define ll long long #define N #defin ...