[北大集训 2021] 简单数据结构

news/2024/10/4 8:20:11/文章来源:https://www.cnblogs.com/lalaouyehome/p/18446272

简单数据结构,但本蒟蒻觉得并不简单呐!

容易发现这题的几个好用的性质:

1.只要被第一个操作影响的都能够保持单调,容易一起维护。

2.操作都是全局的!

3.没被操作一影响的都可以表示为 \(ki+a_i\) 的形式。

利用这些性质,我们考虑把没被操作一影响的项放在 \(S\) 集合,被操作一影响的项放在 \(T\) 集合。现在我们考虑动态维护这两个东西,事实上我们可以先知道每一项是在什么时候从 \(S\) 进入 \(T\) 的(显然初始每一项都在 \(S\))。

每次我们进行操作一时,都会把所有满足 \(a_i\ge v-ki\) 的所有项并入 \(T\),这种一次函数的形式启发我们维护一个凸包,上面每个点为 \((i,a_i)\),然后维护一个上凸包,但是凸包太大了,不好修改,怎么办?我们发现删点与重构凸包复杂度非常不均,所以考虑分块,我们这样每次删掉一个点,再 \(\mathcal{O}(\sqrt n)\) 重构即可。因为只会删掉 \(n\) 个点,所以复杂度是对的,但是这里有个小问题,就是我们单次操作找每个块内凸包的点有可能退化到 \(\mathcal{O}(n)\),没关系,我们的 \(k\) 是单调的,每个块内维护个双指针即可。

对答案的贡献用树状数组可以简单维护。

然后考虑维护 \(T\),首先对于 \(1\) 操作相当于是一段后缀推平,线段树上二分随便做。对于操作二的贡献在线段树上维护增加次数 \(delta\),并且维护可提供贡献的点 \(sum\),因为线段树上可以产生贡献的点并不连续。对于最大值的维护也是简单的,知道区间中最右边的在 \(T\) 中的点就知道最大值了。

时间复杂度 \(\mathcal{O}(n\sqrt n)\),这里 \(n,q\) 同级。

代码:

#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define inf 1000000000
#define id(x, y) n * (x - 1) + y
#define ls p << 1
#define rs ls | 1
using namespace std;
constexpr int N = 2e5 + 5, M = (1ll << 31) - 1, P = 998244353;
constexpr double PI = acos (-1.0);
inline int rd () {int x = 0, f = 1;char ch = getchar ();while (! isdigit (ch)) {if (ch == '-') f = -1;ch = getchar ();}while (isdigit (ch)) {x = (x << 1) + (x << 3) + ch - 48;ch = getchar ();}return x * f;
}
int qpow (int x, int y) {int ret = 1;for (; y; y >>= 1, x = x * x % P) if (y & 1) ret = ret * x % P;return ret;
}namespace seg {class node {public:int sum, val, mx, R, cnt, tag1, tag2;} t[N << 2];void clear () {rep (i, 1, N * 4 - 1) {t[i].sum = t[i].val = 0;t[i].mx = t[i].R = t[i].cnt = 0;t[i].tag1 = - 1; t[i].tag2 = 0;}}void merge (node &ret, node x, node y) {ret.sum = x.sum + y.sum;ret.val = x.val + y.val;ret.mx = max (x.mx, y.mx);ret.R = max (x.R, y.R);ret.cnt = x.cnt + y.cnt;}void cov (int p, int val) {t[p].val = t[p].cnt * val;t[p].mx = val;t[p].tag1 = val;t[p].tag2 = 0;}void add (int p, int x) {t[p].val += t[p].sum * x;t[p].mx += t[p].R * x; t[p].tag2 += x;}void psd (int p) {if (t[p].tag1 > -1) {cov (ls, t[p].tag1);cov (rs, t[p].tag1);t[p].tag1 = -1;}if (t[p].tag2) {add (ls, t[p].tag2);add (rs, t[p].tag2);t[p].tag2 = 0;}}int find (int p, int l, int r, int x) {if (l == r) {if (t[p].val >= x) return l; else return 0;}int mid = l + r >> 1;psd (p);if (t[ls].mx >= x) return find (ls, l, mid, x);else return find (rs, mid + 1, r, x);}void modify (int p, int l, int r, int L, int R, int v) {if (L <= l && r <= R) return cov (p, v), void ();int mid = l + r >> 1; psd (p);if (L <= mid) modify (ls, l, mid, L, R, v);if (R > mid) modify (rs, mid + 1, r, L, R, v);merge (t[p], t[ls], t[rs]);}void upd (int p, int l, int r, int x, int k) {if (l == r) {t[p].sum = x, t[p].cnt = 1;t[p].R = x, t[p].val = t[p].mx = k;return ;} psd (p); int mid = l + r >> 1;if (x <= mid) upd (ls, l, mid, x, k);else upd (rs, mid + 1, r, x, k);merge (t[p], t[ls], t[rs]);}int qry (int p, int l, int r, int L, int R) {if (L <= l && r <= R) return t[p].val;int mid = l + r >> 1, ret = 0; psd (p);if (L <= mid) ret += qry (ls, l, mid, L, R);if (R > mid) ret += qry (rs, mid + 1, r, L, R);return ret;}
}int n, m, q;
int a[N];
struct FWT {int c[N];int lb (int x) { return x & -x; }void upd (int x, int y) {for (; x <= n; c[x] += y, x += lb (x)) ;}int qry (int x) {int ret = 0;for (; x; ret += c[x], x -= lb (x)) ;return ret;}
} s, t;
class node {public:int opt;int l, r;
} g[N];class Dot {public:int x, y;friend Dot operator + (const Dot &a, const Dot &b) {return (Dot) {a.x + b.x, a.y + b.y};}friend Dot operator - (const Dot &a, const Dot &b) {return (Dot) {a.x - b.x, a.y - b.y};}friend int operator * (const Dot &a, const Dot &b) {return a.x * b.y - a.y * b.x;}
} d[N];
vector <int> vec[N];
class block {public:int l, r, ld, rd;int stk[505];void build () {l = 1, r = 0;rep (i, ld, rd) {if (d[i].y < 0) continue;while (l < r && (d[stk[r]] - d[stk[r - 1]]) * (d[i] - d[stk[r]]) >= 0) -- r;stk[++ r] = i;}}void del (int k, int id, int x) {while (l <= r) {while (l < r && d[stk[l]].x * k + d[stk[l]].y <= d[stk[l + 1]].x * k + d[stk[l + 1]].y) ++ l;if (d[stk[l]].x * k + d[stk[l]].y >= x) vec[id].eb (d[stk[l]].x), d[stk[l]].y = -1; else return ;build ();}}
} bl[505];
void init () {int B = sqrt (n);m = n / B + (bool) (n % B);rep (i, 1, m) {bl[i].ld = bl[i - 1].rd + 1;bl[i].rd = min (bl[i - 1].rd + B, n);bl[i].build ();}
}
signed main () {// freopen ("1.in", "r", stdin);// freopen ("1.out", "w", stdout);n = rd (), q = rd ();rep (i, 1, n) a[i] = rd (), d[i] = (Dot) {i, a[i]};init ();int now = 0;rep (i, 1, q) {g[i].opt = rd ();if (g[i].opt == 1) {g[i].l = rd ();rep (j, 1, m) bl[j].del (now, i, g[i].l);} else if (g[i].opt == 2) {++ now;} else g[i].l = rd (), g[i].r = rd ();}rep (i, 1, n) {s.upd (i, i), t.upd (i, a[i]);}seg::clear ();now = 0;rep (i, 1, q) {if (g[i].opt == 1) {int pos = seg::find (1, 1, n, g[i].l);if (pos) seg::modify (1, 1, n, pos, n, g[i].l);for (auto p : vec[i]) {s.upd (p, - p), t.upd (p, - a[p]);seg::upd (1, 1, n, p, g[i].l);}} else {if (g[i].opt == 2) {++ now; seg::add (1, 1);} else {int l = g[i].l, r = g[i].r;printf ("%lld\n", now * (s.qry (r) - s.qry (l - 1)) + t.qry (r) - t.qry (l - 1) + seg::qry (1, 1, n, l, r));}}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/807751.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cisco Secure Network Analytics 7.5.1 发布下载,新增功能概览

Cisco Secure Network Analytics 7.5.1 发布下载,新增功能概览Cisco Secure Network Analytics 7.5.1 发布下载,新增功能概览 Cisco Secure Network Analytics 7.5.1 - 领先的网络检测和响应 (NDR) 解决方案 Secure Network Analytics (formerly Stealthwatch) - Network Vis…

C++ lambda 捕获列表

▲《C++ Primer》 P352

读数据湖仓06数据集成

读数据湖仓06数据集成1. 数据湖仓中的数据集成 1.1. 数据湖仓的总体目标是为每一个人提供支持,包括从普通职员到CEO 1.2. 有了作为基础设施的基础数据,企业等组织才能实现真正的数据驱动 1.3. 提供组织所需的数据,最关键的一环在于提供集成的数据基础1.3.1. 只将数据扔进数据…

MSYS2 环境使用

在 Windows 环境下使用 rusqlite 库碰到了报错:由于 Windows 环境不如 Ubuntu 那样一个 apt install libsqlite3-dev 解决问题,所以采用 MSYS2 来从根源解决问题。 安装MSYS2 官网: WEB PAGE MSYS2 代理镜像下载地址:无 由于 MSYS2 自带的有国内镜像,所以按理说下载好无需配…

Echoism

Echoing reality Are your memories of me? Floating through a state, half asleep, never awake(never awake) I wont breathe in eternity Carrying your secrets feeling close to who you are Youre just beyond my reach A passing breeze, And your final moments se…

快乐数学1培养数学直觉

1 培养数学直觉我们最初接触一个概念时,会形成我们的直觉。而我们的直觉会影响我们对一门学科的喜爱程度。什么意思呢? 假设我们想给 “猫 ”下一个定义:古代的定义: 一种毛茸茸的动物,有爪子、牙齿、尾巴和四条腿,高兴时发出咕噜声,生气时发出嘶嘶声。 进化定义: 某一…

SciTech-Mathmatics-Markdown:List 嵌入 code block + LaTex: 论文写作、排版与使用 + 数学公式的输入方式

民主与共和 更好的共和度保障更高级的民主, 是因为 民主 与 共和 是统一的。 平衡态的“跃迁”是需要“吸收足够能量”, "改变"总是需要"成本"的。 在正确的方向上,每一天的学习是“质变飞跃”的必要。Markdown: List 嵌入 code block Code is possible …

简单讲讲上下界网络流

无源汇可行流 无源汇网络流一般不讨论最大流,因为它的流都是环流,分布在各个位置,一是不好统计,二是一般也没有意义。所以一般建图只需要求是否有可行解(但我也没遇到过求输出YES和NO的可行流题目,网上的博客也都只当做有源汇的前置知识讲了) 废话不多说,直接上图。第一…

Netflix 錯誤 NW-8-18

环境 PS5的奈飞,OpenWrt的树莓派做软路由解决方案 首先重置,如果不行,关机拔掉电源线等待三分钟,重试 Netflix。如果这篇文章对你有用,可以关注本人微信公众号获取更多ヽ(^ω^)ノ ~

Python算法学习

算法学习心得,源码均为Python实现目录绪论数据结构算法算法的特征算法的评价算法的时间复杂度算法的空间复杂度递归汉诺塔问题(递归调用)查找排序二分查找检查排序是否完成冒泡排序选择排序插入排序希尔排序(高级版插入排序)快速排序堆排序(二叉树)python中内置好的堆排…

数学建模学习

数学建模学习,包含各种常用模型和Matlab源码目录 目录目录评价类方法层次分析法搜索引擎算法步骤算法代码F4锁定单元格优劣解距离法算法步骤算法代码自输入权重代码基于熵权法权重的代码灰色关联分析传统数理统计的不足之处该方法的好处算法步骤算法代码基于灰色关联度权重的代…

下载、安装、配置 android-studio-2021.1.1.22-windows

软件安装包:图1 软件安装包提示删除已经存在的版本:图2 提示删除已经存在的版本根据提示选择是:图3 根据提示选择是继续安装:图4图5图6图7图8图9图10