*I. P6604 [HNOI2016]序列 加强版

摘自学习笔记 简单树论 笛卡尔树部分例题 I.

P6503 比较类似。我们设 \(f_i\) 表示全局以 \(i\) 结尾的子区间的最小值之和,令 \(p_i\) 为下标在 \(i\) 之前第一个比 \(a_i\) 小的位置,显然有 \(f_i=f_{p_i}+(i-p_i)a_i\):因为 \(a_i\) 对 \(p_i\) 以及 \(p_i\) 以前的最小值没有影响(即 \([1,p_i]\) 与 \([1,i]\),\([2,p_i]\) 与 \([2,i]\cdots\) \([p_i,p_i]\) 与 \([p_i,i]\) 的最小值相同),所以可以直接由 \(f_{p_i}\) 转移得来。而根据 \(p_i\) 的定义,后面 \(i-p_i\) 个子序列(即 \([p_i+1,i],[p_i+2,i]\cdots,[i,i]\))的最小值为 \(a_i\)。

注意到 \(p_i\) 实际相当于 \(i\) 在笛卡尔树上第一个向左走的父亲,求 \(p_i\) 的过程十分类似构建笛卡尔树:笛卡尔树上每个节点的祖先由左右两个单调栈构成

考虑对一个区间求答案:求出区间最小值的位置 \(p\),那么左端在 \(p\) 左边,右端在 \(p\) 右边的子区间最小值为 \(a_p\),故答案加上 \(a_p\times (p-l+1)\times (r-p+1)\)。此外,我们还需求出 \([l,p)\) 与 \((p,r]\) 的答案:考虑 \((p,r]\) 每个位置对答案的贡献都是 \(f_r-f_p\),因为 \([i,p]\) 与 \([i,r]\ (1\leq i\leq p)\) 的最小值相同。前缀和优化可以做到 \(\mathcal{O}(1)\) 回答每个询问。对于 \([l,p)\) 同理,我们只需预处理出 \(g_i\) 表示全局以 \(i\) 开头的子区间的最小值之和并类似处理即可。

复杂度瓶颈在于区间 RMQ,时间复杂度 \(\mathcal{O}(n\log n+q)\)。

const int N = 1e5 + 5;
const int K = 17; namespace gen {
ull s, a, b, c, las = 0;
ull rand() {return s ^= (a + b * las) % c;}
} int n, q, type, stc[N], *top = stc, a[N], lg[N], pre[N], suf[N];
ll mi[K][N], fp[N], gp[N], fs[N], gs[N]; ull res;
int cmp(int x, int y) {return a[x] < a[y] ? x : y;}
int RMQ(int l, int r) {int d = lg[r - l + 1]; return cmp(mi[d][l], mi[d][r - (1 << d) + 1]);} int main(){
cin >> n >> q >> type;
for(int i = 1; i <= n; i++) a[i] = read(), mi[0][i] = i;
for(int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;
for(int i = 1; i <= lg[n]; i++)
for(int j = 1; j + (1 << i) - 1 <= n; j++)
mi[i][j] = cmp(mi[i - 1][j], mi[i - 1][j + (1 << i - 1)]);
for(int i = 1; i <= n; i++) {
while(*top && a[*top] >= a[i]) suf[*top--] = i; // 可以类比求笛卡尔树的过程: ls[i] = *top, 因此 suf[*top] = i;
pre[i] = *top, *++top = i; // 同理, rs[*top] = i, 所以 pre[i] = *top: 笛卡尔树上每个节点的祖先是由两个单调栈构成的!
}
for(int i = 1; i <= n; i++)
fp[i] = fp[pre[i]] + 1ll * a[i] * (i - pre[i]), gp[i] = gp[i - 1] + fp[i];
for(int i = n; i; i--)
fs[i] = fs[suf[i]] + 1ll * a[i] * (suf[i] - i), gs[i] = gs[i + 1] + fs[i];
if(type) gen :: s = read(), gen :: a = read(), gen :: b = read(), gen :: c = read();
for(int i = 1, l, r; i <= q; i++) {
if(type == 0) l = read(), r = read();
else {
l = gen :: rand() % n + 1;
r = gen :: rand() % n + 1;
if(l > r) swap(l, r);
}
ll p = RMQ(l, r), ans;
ans = a[p] * (r - p + 1) * (p - l + 1);
ans += gp[r] - gp[p] - fp[p] * (r - p);
ans += gs[l] - gs[p] - fs[p] * (p - l);
res ^= gen :: las = ans;
}
cout << res << endl;
return flush(), 0;
}

最新文章

  1. HL7 2.6解析转XML(C#版)
  2. HTTP 错误 403.14&ndash;Forbidden错误解决
  3. storyboard
  4. [CAMCOCO][C#]我的系统架构.服务器端.(三)----Model层
  5. BOOTCAMP版本适配机型表
  6. 网站服务管理系统wdcp简介及功能特性
  7. Word Ladder II 2015年6月4日
  8. Eclipse安卓开发环境搭建
  9. [福州大学]W班平时成绩排名
  10. Ribbon负载均衡策略配置
  11. Win10提示无法创建新的分区也找不到现有的分区解法
  12. freeswitch黑名单mod_blacklist使用
  13. 01-Python的基础知识2
  14. HDU 1867 A + B for you again 字符匹配
  15. Apache伪静态配置,支持.htaccess配置方法
  16. Git_搭建Git服务器
  17. php中ignore_user_abort函数的用法(定时)
  18. Windows下基于eclipse的Storm应用开发与调试
  19. myeclipse 配置
  20. flink 根据时间消费kafka

热门文章

  1. LeetCode:回溯算法
  2. UltraSoft - Beta - Scrum Meeting 8
  3. [no code][scrum meeting] Alpha 13
  4. Linux C 数据结构 -&gt;单向链表
  5. 清除行列 牛客网 程序员面试金典 C++ Python
  6. Swift-技巧(二)模糊脸部功能
  7. 谷歌chrome多个相同用户登陆同一个机器多开配置
  8. robot_framewok自动化测试--(9)连接并操作 MySql 数据库
  9. 端口被占用(启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099的解决办法)
  10. STC单片机控制28BYJ-48步进电机