Description

给定一个长度为 \(n\) 的非负整数序列 \(\{a_n\}\),\(q\) 次操作,每次要么单点修改序列某个值,要么查询整个序列需要操作多少次才能变成全 \(0\)。

一次操作是指:找到序列的最大值的位置,如果有多个最大值则取最左边的,然后将这个数和这个位置左右紧挨着的数都 \(-1\),如果减到 \(0\) 则不减。

Limitation

\(1~\leq~n,~q~\leq~10^5\)

序列值域在 \(10^9\) 范围内。

Solution

第一次写 YnOI 体验极差

首先注意到的是如果确定要操作某个位置 \(x\) 了,那么最终这个位置一定被操作了 \(a_x\) 次。原因是这个位置每操作一次,左右都会减一,这样这个位置永远不会因为要操作左右而减小,所以让这个位置变成 \(0\) 的唯一可能只有操作这个位置本身。于是找到一个位置将它一直操作到 \(0\) 与原操作方式是等价的。于是问题被转化成了求所有会被操作位置的数字和。

先设序列中的数互不相同。考虑序列中一个单调递增或者单调递减的极长子序列,首先会操作最大值,减到 \(0\) 以后次大值一定也被减到了 \(0\),然后再操作次次大值,然后次次次大也减到 \(0\) 了……一直这么下去发现所有被操作位置的奇偶性是相同的,即在这个极长单调序列中所有位置与最大值位置的奇偶性相同的点都会被操作。考虑用 set 维护序列中所有极值点,用两个树状数组分别奇数下标的前缀和和偶数下标的前缀和,即可求出初始序列的操作次数。

考虑修改的时候,只需要继续修改序列的极值点即可。

于是你就要面对这个点本来是极值点,本来不是极值点。他左边是极值点,右边是极值点,都不是极值点,改完以后极值位置不变,改完以后新增一个极大值,新增一个极小值等等十几种情况

考虑手动讨论每种情况显然非常不靠谱,但是注意到修改某个位置最多只会影响到这个位置向左右分别数两个极值点(不包括自身)这段区间的情况,同时新可能增加或者删除的极值点只有这个位置和这个位置左右各一个位置共三个位置。于是可以暴力重构这段区间的答案,由于求答案的时候只需要扫描区间内所有极值点,而极值点个数又是常数级别的,于是可以 \(O(\log n)\) 的去修改。这个 \(\log\) 是由于 setlower_bound 造成的。

解释一下为什么会影响到左右数第二个极值点,如下数据:

9 2 6 8

三个极值点分别是 \(1,2,4\),其中 \(2\) 是极小值,\(1,4\) 是极大值。如果将位置 \(1\) 修改为 \(1\),那么极值点变成了 \(1,4\),由此,\([2,4]\) 这段区间不复存在,变成了 \([1,4]\) 这段区间,需要重新统计,影响到了 \(1\) 向右数第 \(2\) 个极值点 \(4\)。

考虑如果序列中有相同的数怎么办:

如果相同的数不连续,那么根本不用管。如果连续,先假设这个这组数的第一个数大于左侧的数,那么操作到这组数的时候,这个数会被最先操作,于是这组数的第一个位置应该被设为极大值。如果这组数的第一个数小于左侧的数,那么第一个数是否被操作不由这个数决定,它不应该成为极小值。

考虑这组数的最后一个数,如果它大于右侧的数,那么这个数操作完以后会继续操作右侧的数,它不应该成为极大值。如果它小于左侧的数,那么左右两侧的区间都会在操作到这个位置的时候停止,那么这个位置应该成为极小值。

有一些细节:

考虑一个极小值会被操作,当且仅当它左右的数都没有被操作,那么它不会被减掉,只能自己单独操作。这种情况即它到左右的极大值点的距离都是偶数。

在扫描区间答案的时候,如果区间有 \(x\) 个极值点,那么只需要考虑 \(x-1\) 段区间的答案,因此只需要扫描 \(x-1\) 个极值点。但是需要注意到的是不能漏掉剩下那个极值点是极小值的讨论。

Code

参考了 @FlushHu 神仙的代码,在此表示感谢。

#include <cstdio>
#include <set>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endiftypedef long long int ll;namespace IPT {const int L = 1000000;char buf[L], *front=buf, *end=buf;char GetChar() {if (front == end) {end = buf + fread(front = buf, 1, L, stdin);if (front == end) return -1;}return *(front++);}
}template <typename T>
inline void qr(T &x) {char ch = IPT::GetChar(), lst = ' ';while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();if (lst == '-') x = -x;
}namespace OPT {char buf[120];
}template <typename T>
inline void qw(T x, const char aft, const bool pt) {if (x < 0) {x = -x, putchar('-');}int top=0;do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);while (top) putchar(OPT::buf[top--]);if (pt) putchar(aft);
}const int maxn = 100005;int n, dn;
ll ans;
ll MU[maxn], odd[maxn], eve[maxn];
std::set<int>s;void check(const int x);
void upd(const int x);
void calc(const int ll, const int rr, const int v);int main() {freopen("1.in", "r", stdin);qr(n); dn = n + 1;s.insert(0); s.insert(n + 1);for (int i = 1; i <= n; ++i) {upd(i);}int q = 0, x;qr(q);while (q--) {x = 0; qr(x);upd(x);printf("%lld\n", ans);}return 0;
}inline int lowbit(const int x) { return x & -x; }void update(ll *const a, int p, const ll v) {while (p <= dn) {a[p] += v;p += lowbit(p);}
}ll query(ll *const a, int p) {ll _ret = a[p];do _ret += a[p -= lowbit(p)]; while (p);return _ret;
}void upd(const int x) {ll y = 0; qr(y);auto v = s.lower_bound(x);auto l = v, r = v;--l; ++r;if (l != s.begin()) --l;if ((r != s.end()) && (*v == x)) ++r;if (r == s.end()) --r;calc(*l, *r, -1);update(x & 1 ? odd : eve, x, y - MU[x]); MU[x] = y;check(x);if (x != 1) check(x - 1);if (x != n) check(x + 1);calc(*l, *r, 1);
}void check(const int x) {if ((MU[x] > MU[x - 1]) != (MU[x] < MU[x + 1])) s.insert(x);else s.erase(x);
}void calc(const int ll, const int rr, const int v) {auto l = s.lower_bound(ll), r = s.lower_bound(rr);while (r != l) {auto t = r; --t;if (MU[*t] < MU[*r]) {auto ad = *r & 1 ? odd : eve;ans += v * (query(ad, *r) - query(ad, *t));} else {auto ad = *t & 1 ? odd : eve;ans += v * (query(ad, *r - 1) - query(ad, *t));auto l0 = r, r0 = r;if (l0 != s.end()) --l0;++r0; if (r0 == s.end()) --r0;if ((!((*r - *l0) & 1)) && (!((*r0 - *r) & 1))) {ans += MU[*r] * v;}}--r;}if (MU[*l] >= MU[*l + 1]) return;auto l0 = r, r0 = r;if (l0 != s.end()) --l0;++r0; if (r0 == s.end()) --r0;if ((!((*r - *l0) & 1)) && (!((*r0 - *r) & 1))) {ans += MU[*r] * v;}
}

转载于:https://www.cnblogs.com/yifusuyi/p/11108521.html

【树状数组】【P5069】[Ynoi2015]纵使日薄西山相关推荐

  1. 洛谷P5069 [Ynoi2015]纵使日薄西山(树状数组,set)

    洛谷题目传送门 一血祭 向dllxl致敬! 算是YNOI中比较清新的吧,毕竟代码只有1.25k. 首先我们对着题意模拟,寻找一些思路. 每次选了一个最大的数后,它和它周围两个数都要减一.这样无论如何, ...

  2. 洛谷P3987 我永远喜欢珂朵莉~ 树状数组+vector(暴力)

    题目链接:我永远喜欢珂朵莉- 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去.逐渐消逝的未来.我回来了,纵使日薄西山,即便看不到 ...

  3. 洛谷 P5057 [CQOI2006]简单题(树状数组)

    嗯... 题目链接:https://www.luogu.org/problem/P5057 首先发现这道题中只有0和1,所以肯定与二进制有关.然后发现这道题需要支持区间更改和单点查询操作,所以首先想到 ...

  4. Color the ball(HDU1556)树状数组

    每次对区间内气球进行一次染色,求n次操作后后所有气球染色次数. 树状数组,上下区间更新都可以,差别不大. 1.对于[x,y]区间,对第x-1位减1,第y位加1,之后向上统计 #include<b ...

  5. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  6. Codeforces 629D Babaei and Birthday Cake(树状数组优化dp)

    题意: 线段树做法 分析: 因为每次都是在当前位置的前缀区间查询最大值,所以可以直接用树状数组优化.比线段树快了12ms~ 代码: #include<cstdio> #include< ...

  7. poj_3067 树状数组

    题目大意 左右两个竖排,左边竖排有N个点,从上到下依次标记为1,2,...N; 右边竖排有M个点,从上到下依次标记为1,2....M.现在从K条直线分别连接左边一个点和右边一个点,求这K条直线的交点个 ...

  8. hdu 1166 敌兵布阵(树状数组)

    题意:区间和 思路:树状数组 #include<iostream> #include<stdio.h> #include<string.h> using names ...

  9. Equalizing Two Strings 冒泡排序or树状数组

    首先考虑排序后相等 如果排序后相等的话就只考虑reverse长度为2的,所以a或者b排序后存在相邻两个字母相等的话就puts YES,n>26也直接puts YES 不然的话就假设c为a,b排完 ...

最新文章

  1. 孟天广做客社科大讲堂 阐释计算社会科学发展与文理交叉
  2. 请问有办法加速TTS的反应时间吗
  3. gatdata获取曲线_GetData软件使用--获取曲线图中的数据
  4. Linux - CentOS 6.3 (x86_64)安装过程详细图解
  5. python基础教程:强制数据类型转换教程及实例
  6. 在python语言中下列是二进制整数_Python从菜鸟到高手(5):数字
  7. 企业 MySQL 优化实施方案
  8. 无法打开计算机上的event log服务,Win7系统下启用Windows event log服务发生4201错误的正确解决方法...
  9. 辐射避难所服务器维护,《辐射:避难所Online》6月2日停服维护更新公告
  10. git checkout
  11. 交换机 路由器 三层交换机和路由器应用区别
  12. 润乾报表-数据源的选取不能选视图
  13. struts2之拦截器详解
  14. 计算机培训坊主总结,信息技术教学培训心得体会
  15. Mac必备开源鼠标手势软件 MacStroke
  16. Opencv python 直方图处理
  17. 各种定律(心理学定律、思考定律)
  18. 最新版本飞信协议抓包
  19. 怎么制作表情DIY,动态GIF表情包如何制作?
  20. 量子计算机不能解决的问题,量子计算机破产问题传统计算机无法解决

热门文章

  1. @微信官方,给我一个小老虎图标
  2. 机器人抓取 三维重建机器人抓取 三维物体匹配
  3. 区块链之旅(四)双花攻击、博弈论、Hash函数、数字签名
  4. 绝对让你怀疑人生的游戏榜,游戏建模跟《人类一败涂地》很相似
  5. Android 音视频开发(三) -- Camera2 实现预览、拍照功能
  6. 电脑网线,电脑网线插了没反应怎么回事?如何解决?
  7. 我的世界服务器个体值怎么修改,我的世界神奇宝贝个体值指令 | 手游网游页游攻略大全...
  8. 【JokerのZYNQ7020】TIMER。
  9. 社交系统ThinkSNS+ 性能简述
  10. flutter git 拉不起来_这些基础不牢固,我们的蛙泳就别想拉起来