P9993 [Ynoi Easy Round 2024] TEST_133 题解
题目链接: [Ynoi Easy Round 2024] TEST_133
首先历史最大加,吉司机跑不掉了,维护历史最大加标记以及历史最大,那么根据吉司机标记思想更新操作应该为
\]
新的历史最大值,由原来的历史最大值和当前点的值加上更新过程中最大的历史加标记二者取最优。
看题目条件,好家伙时间限制 \(40s\)。有个很烦的限制 \(a_i < x\) 的最大历史值。那么很明显的是一个区间内的历史最大值是很好都拿到的,每个数也是很好都拿到的,但是这里面不是所有数都有贡献,有啥办法可以快速找到需要判断的数?emmmm,有序好像就特别好做了。直接二分出最大的满足 \(a_j<x\) 的 \(j\)。区间内要有序,然后 \(40s\) 时限的提醒。自然而然想到了根号级做法。分块的入门 P2801 教主的魔法。维护块内有序即可二分。
需要维护什么信息仔细想想。
1.首先每个块需要有 lazy 标记。非常简单:最基本的区间加标记和吉司机思想的历史最大加标记。
2.块内有序,是按照 \(a_i\) 进行排序,而我们显然在查询时可以知道贡献区间为 \(1 \sim j\),其中 \(j\) 是可以二分出来的最大的满足 \(a_j < x\) 的 \(j\)。而我们需要知道这个前缀区间的最大历史值。很简单。维护块内有序的同时,并维护对应排序后的 \(a_i\) 对应位置的 \(h_{max}\) 的前缀最大值。
然后,然后就完了。剩下的就是卡常和常规的 DS 码工了。
考虑几个点的复杂度
1、对于重构一个块,根号重构。我们需要复制一份对应的 \((a_i,h_i)\),然后排序,然后再更新块内的 \(PrefixMax_{h_i}\)。这个复杂度显然是
\]
2、对于一次 pushDown 更新标记,我们就是正常一遍块内遍历更新。根据上述先后更新 \(h_{max}\) 与 \(a_i\)。复杂度为 \(O(\sqrt{n})\)
3、二分出块内小等于 \(<x\) 的最大历史最值前缀max(区间max具有单调性)。这个复杂度显然为 \(O(\log{\sqrt{n}})\)
4、修改时,还是老规矩,单块内就暴力,多块就散块暴力,整块打标记更新。需要注意的是散块需要记得先 pushDown 以后再更新。然后优化下常数,其实可以开个 vis 数组,也可以当做标记的一种,记录哪些块发生了变化,需要在后续查询中重构。因为重构的复杂度是较高 的,所以我们也可以当做 lazy 去写。这里的复杂度显然是 \(O(\sqrt{n})\)
5、查询时,需要把该重构的重构一下。然后注意整块不要 pushDown,不然每个块都 pushDown 复杂度就错了,应该当做标记永久化的思想:查询时用 \(x-add\) 就行了,不需要 pushDown 以后的新 \(a_i\) 去算。然后就纯每个块二分。复杂度为 \(O(\sqrt{n}\log{\sqrt{n}})\)
6、建块时每个块需要 rebuild 一下,显然是 \(O(\sqrt{n} \times \sqrt{n}\log{\sqrt{n}})=O(n\log{\sqrt{n}})\),当然也可以全部记录为 \(vis\) 为 true 后更新。
参考代码
#include <bits/stdc++.h>
//#pragma GCC optimize("Ofast,unroll-loops")
#define isPbdsFile
#ifdef isPbdsFile
#include <bits/extc++.h>
#else
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope>
#endif
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef __int128 i128;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
template <typename T>
int disc(T* a, int n)
{
return unique(a + 1, a + n + 1) - (a + 1);
}
template <typename T>
T lowBit(T x)
{
return x & -x;
}
template <typename T>
T Rand(T l, T r)
{
static mt19937 Rand(time(nullptr));
uniform_int_distribution<T> dis(l, r);
return dis(Rand);
}
template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{
return (a % b + b) % b;
}
template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{
a %= c;
T1 ans = 1;
for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c;
return modt(ans, c);
}
template <typename T>
void read(T& x)
{
x = 0;
T sign = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')sign = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
x *= sign;
}
template <typename T, typename... U>
void read(T& x, U&... y)
{
read(x);
read(y...);
}
template <typename T>
void write(T x)
{
if (typeid(x) == typeid(char))return;
if (x < 0)x = -x, putchar('-');
if (x > 9)write(x / 10);
putchar(x % 10 ^ 48);
}
template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{
write(x), putchar(c);
write(c, y...);
}
template <typename T11, typename T22, typename T33>
struct T3
{
T11 one;
T22 tow;
T33 three;
bool operator<(const T3 other) const
{
if (one == other.one)
{
if (tow == other.tow)return three < other.three;
return tow < other.tow;
}
return one < other.one;
}
T3() { one = tow = three = 0; }
T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
{
}
};
template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{
if (x < y)x = y;
}
template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{
if (x > y)x = y;
}
constexpr int N = 5e5 + 10;
constexpr ll INF = 1e18 + 10;
int pos[N];
constexpr int SIZE = sqrt(N);
constexpr int CNT = (N + SIZE - 1) / SIZE;
int s[CNT + 1], e[CNT + 1];
ll a[N]; //当前序列
ll his[N]; //单点最大历史值
pll sortA[N]; //块内有序,并且附带对应的单点历史最大值
ll preHisMax[N]; //块内前缀历史最大值
bool vis[CNT + 1]; //需要重构块
struct Tag
{
ll add; //加法标记
ll hadd; //历史最大加
} tag[CNT + 1];
inline void rebuild(const int id)
{
forn(i, s[id], e[id])sortA[i] = pll(a[i], his[i]);
sort(sortA + s[id], sortA + e[id] + 1); //按当前序列排序
//更新块内基于原序列为有序序列的前缀历史最大值
preHisMax[s[id]] = sortA[s[id]].second;
forn(i, s[id]+1, e[id])uMax(preHisMax[i] = sortA[i].second, preHisMax[i - 1]);
}
inline void push_down(const int id)
{
if (!tag[id].add and !tag[id].hadd)return;
forn(i, s[id], e[id])uMax(his[i], a[i] + tag[id].hadd), a[i] += tag[id].add; //更新当前序列并且更新当前历史最大值
tag[id] = {0, 0}; //清空lazy
}
//二分出块内小于x的最大历史最值前缀max(区间max具有单调性)
inline ll binary(const int id, const ll x)
{
int l = s[id], r = e[id];
if (sortA[l].first >= x)return -INF;
while (l < r)
{
if (const int mid = l + r + 1 >> 1; sortA[mid].first < x)l = mid;
else r = mid - 1;
}
return max(preHisMax[l], sortA[l].first + tag[id].hadd);
}
inline ll query(const int l, const int r, const ll x)
{
const int L = pos[l], R = pos[r];
if (L == R)
{
if (vis[L])rebuild(L), vis[L] = false;
ll ans = -INF;
forn(i, l, r)if (a[i] + tag[L].add < x)uMax(ans, max(his[i], a[i] + tag[L].hadd));
return ans;
}
if (vis[L])rebuild(L), vis[L] = false;
if (vis[R])rebuild(R), vis[R] = false;
ll ans = -INF;
forn(i, l, e[L])if (a[i] + tag[L].add < x)uMax(ans, max(his[i], a[i] + tag[L].hadd));
forn(i, s[R], r)if (a[i] + tag[R].add < x)uMax(ans, max(his[i], a[i] + tag[R].hadd));
forn(i, L+1, R-1)
{
if (vis[i])rebuild(i), vis[i] = false;
if (ll t = binary(i, x - tag[i].add); t != -INF)uMax(ans, t);
}
return ans;
}
inline void add(const int l, const int r, const ll x)
{
const int L = pos[l], R = pos[r];
if (L == R)
{
push_down(L);
forn(i, l, r)uMax(his[i], a[i] += x);
vis[L] = true;
return;
}
push_down(L), push_down(R);
forn(i, l, e[L])uMax(his[i], a[i] += x);
forn(i, s[R], r)uMax(his[i], a[i] += x);
vis[L] = vis[R] = true;
forn(i, L+1, R-1)uMax(tag[i].hadd, tag[i].add += x);
}
int n, q;
inline void solve()
{
cin >> n >> q;
int siz = sqrt(n);
int cnt = (n + siz - 1) / siz;
forn(i, 1, n)cin >> a[i], his[i] = a[i], pos[i] = (i - 1) / siz + 1;
forn(i, 1, cnt)s[i] = (i - 1) * siz + 1, e[i] = i * siz;
e[cnt] = n;
forn(i, 1, cnt)rebuild(i);
forn(i, 1, q)
{
int op, l, r, val;
cin >> op >> l >> r >> val;
if (op == 1)add(l, r, val);
else
{
if (ll ans = query(l, r, val); ans == -INF)cout << "-inf" << endl;
else cout << ans << endl;
}
}
}
signed int main()
{
Spider
//------------------------------------------------------
int test = 1;
// read(test);
// cin >> test;
forn(i, 1, test)solve();
// while (cin >> n, n)solve();
// while (cin >> test)solve();
}
P9993 [Ynoi Easy Round 2024] TEST_133 题解的更多相关文章
- Codeforces Round #539 Div1 题解
Codeforces Round #539 Div1 题解 听说这场很适合上分QwQ 然而太晚了QaQ A. Sasha and a Bit of Relax 翻译 有一个长度为\(n\)的数组,问有 ...
- UOJ Easy Round#7
UOJ Easy Round#7 传送门:http://uoj.ac/contest/35 题解:http://matthew99.blog.uoj.ac/blog/2085 #1 题意: 在一个(2 ...
- Codeforces Round #543 Div1题解(并不全)
Codeforces Round #543 Div1题解 Codeforces A. Diana and Liana 给定一个长度为\(m\)的序列,你可以从中删去不超过\(m-n*k\)个元素,剩下 ...
- Codeforces Round #545 Div1 题解
Codeforces Round #545 Div1 题解 来写题解啦QwQ 本来想上红的,结果没做出D.... A. Skyscrapers CF1137A 题意 给定一个\(n*m\)的网格,每个 ...
- CF Educational Round 78 (Div2)题解报告A~E
CF Educational Round 78 (Div2)题解报告A~E A:Two Rival Students 依题意模拟即可 #include<bits/stdc++.h> us ...
- Educational Codeforces Round 64 部分题解
Educational Codeforces Round 64 部分题解 不更了不更了 CF1156D 0-1-Tree 有一棵树,边权都是0或1.定义点对\(x,y(x\neq y)\)合法当且仅当 ...
- CF Round #580(div2)题解报告
CF Round #580(div2)题解报告 T1 T2 水题,不管 T3 构造题,证明大约感性理解一下 我们想既然存在解 \(|a[n + i] - a[i]| = 1\) 这是必须要满足的 既然 ...
- Educational Codeforces Round 64部分题解
Educational Codeforces Round 64部分题解 A 题目大意:给定三角形(高等于低的等腰),正方形,圆,在满足其高,边长,半径最大(保证在上一个图形的内部)的前提下. 判断交点 ...
- 【题解】Comet OJ Round 70 简要题解
[题解]Comet OJ Round 70 简要题解 A 将放在地上的书按照从小到大排序后,问题的本质就变成了合并两个序列使得字典序最小.可以直接模拟归并排序.直接用循环和std::merge实现这个 ...
- Codeforces Round div2 #541 题解
codeforces Round #541 abstract: I构造题可能代码简单证明很难 II拓扑排序 III并查集 启发式排序,带链表 IV dp 处理字符串递推问题 V 数据结构巧用:于二叉树 ...
随机推荐
- Java解析上传的zip文件--包含Excel解析与图片上传
Java解析上传的zip文件--包含Excel解析与图片上传 前言:今天遇到一个需求:上传一个zip格式的压缩文件,该zip中包含人员信息的excel以及excel中每行对应的人的图片,现在需要将该z ...
- vue学习笔记 八、toRef的使用
系列导航 vue学习笔记 一.环境搭建 vue学习笔记 二.环境搭建+项目创建 vue学习笔记 三.文件和目录结构 vue学习笔记 四.定义组件(组件基本结构) vue学习笔记 五.创建子组件实例 v ...
- Zookeeper 实现 ssl 双向认证
本文为博主原创,未经允许不得转载: zookeeper 作为注册中心或服务发现协调中心的时候,zookeeper 默认与其他服务通过 http 进行通信. zookeeper 与协调服务配置 ssl ...
- 使用Swagger,在编写配置类时报错Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
1.问题 Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet. ...
- 关于编写C时的调试--VS,VSCODE,DEV-C++
1.问题 VS最大的问题是不支持scanf函数,后面的调试部分我就没试了,主要用VS来写C++ VSCODE是服了他的C/C++插件,我死活卡在debug中scanf的输入部分,集成终端根本无法输入, ...
- js - 元素 scrollTop 设置无效的原因 及 解决办法
原因 : 元素 display : flex ; 解决方法 : display : block;
- 【Nginx系列】(一)Nginx基础概念
有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 文章更新计划 系列文章地址 Nginx的三个主要应用场景 静态 ...
- [转帖]PostgreSQL配置文件--WAL
2022-12-23 3.1 Settings 3.1.1 fsync 字符串 默认: fsync = on 开启后强制把数据同步更新到磁盘,可以保证数据库将在OS或者硬件崩溃的后恢复到一个一致的状态 ...
- github-keydb 知识
https://github.com/Snapchat/KeyDB KeyDB is now a part of Snap Inc! Check out the announcement here R ...
- 一次w3wp出现crash的简单解决方案
1. 前几天同事求助, 说一台服务器iis出现多次崩溃的现象,重启iis就可以了. 具体原因不明. 之前遇到过类似的问题 感觉最彻底的解决方案是 抓dump然后使用windbg 进行分析. 但是自 ...