博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BZOJ 3489] A simple rmq problem 【可持久化树套树】
阅读量:5100 次
发布时间:2019-06-13

本文共 3785 字,大约阅读时间需要 12 分钟。

题目链接:

 

题目分析

“因为是OJ上的题,就简单点好了。”——出题人

真的..好..简单...

首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有相同的数,prev[i] = 0。

再求出每个数的后一个与它相同的数的位置,即 next[i], 如果后面没有相同的数,next[i] = n + 1。

这样,对于 l > prev[i], r < next[i] 的区间,i 这个数在区间中至多出现一次。

那么我们要求的就是:符合 prev[i] < l, next[i] > r, l <= i <= r 的最大的 value[i] 。

这样我们可以用可持久化树套树来做。

将所有的数按照 prev[i] 从小到大排序,然后按照这个顺序建立外层的可持久化线段树,每棵可持久化线段树的节点代表的是 next[i] 的区间,每个节点都是一颗可持久化线段树,内层可持久化线段树的节点代表的是 i 的区间,即数在原数列中的位置。

每次 Insert 一个 i ,是在前一棵可持久化线段树的基础上根据这个 i 的 next[i] 增加一条链,然后链上的 logn 个节点都要更新一下它们的内层可持久化线段树,每棵内层线段树也是在之前的内层可持久化线段树的基础上新建一条链,这样总的空间复杂度是 O(n log^2n) 的。

询问 (l, r) 的时候,二分找到一个最大的 p ,满足 prev[p] < l,然后在 p 的外层可持久化线段树中查询 [r + 1, n + 1],即 next > r ,在这个区间的内层可持久化线段树中查找在 [l, r] 区间中的最大值。

时间复杂度也是 O(n log^2n) 的。

 

代码

#include 
#include
#include
#include
#include
#include
using namespace std;inline void Read(int &Num){ char c = getchar(); bool Neg = false; while (c < '0' || c > '9') { if (c == '-') Neg = true; c = getchar(); } Num = c - '0'; c = getchar(); while (c >= '0' && c <= '9') { Num = Num * 10 + c - '0'; c = getchar(); } if (Neg) Num = -Num;}inline int gmin(int a, int b) {return a < b ? a : b;}inline int gmax(int a, int b) {return a > b ? a : b;}const int MaxN = 100000 + 5, MaxNodeI = 2000000 + 5, MaxNodeII = 40000000 + 5;int n, m, Ans, IndexI, IndexII;int Last[MaxN], Root_I[MaxN], Son_I[MaxNodeI][2], Root_II[MaxNodeI], Son_II[MaxNodeII][2], T[MaxNodeII]; struct ES{ int Pos, Num, Prev, Next; bool operator < (const ES &b) const { return Prev < b.Prev; } bool operator < (const int &b) const { return Prev < b; }} E[MaxN];void Insert_II(int &x, int Last, int s, int t, int Pos, int Num){ if (x == 0) x = ++IndexII; T[x] = gmax(T[Last], Num); if (s == t) return; int m = (s + t) >> 1; if (Pos <= m) { Son_II[x][1] = Son_II[Last][1]; Insert_II(Son_II[x][0], Son_II[Last][0], s, m, Pos, Num); } else { Son_II[x][0] = Son_II[Last][0]; Insert_II(Son_II[x][1], Son_II[Last][1], m + 1, t, Pos, Num); }}void Insert_I(int &x, int Last, int s, int t, int Nxt, int Pos, int Num){ if (x == 0) x = ++IndexI; Insert_II(Root_II[x], Root_II[Last], 0, n + 1, Pos, Num); if (s == t) return; int m = (s + t) >> 1; if (Nxt <= m) { Son_I[x][1] = Son_I[Last][1]; Insert_I(Son_I[x][0], Son_I[Last][0], s, m, Nxt, Pos, Num); } else { Son_I[x][0] = Son_I[Last][0]; Insert_I(Son_I[x][1], Son_I[Last][1], m + 1, t, Nxt, Pos, Num); }}int Get_II(int x, int s, int t, int l, int r){ if (x == 0) return 0; if (l <= s && r >= t) return T[x]; int ret = 0, m = (s + t) >> 1; if (l <= m) ret = gmax(ret, Get_II(Son_II[x][0], s, m, l, r)); if (r >= m + 1) ret = gmax(ret, Get_II(Son_II[x][1], m + 1, t, l, r)); return ret;}int Get_I(int x, int s, int t, int l_I, int r_I, int l_II, int r_II){ if (x == 0) return 0; if (l_I <= s && r_I >= t) return Get_II(Root_II[x], 0, n + 1, l_II, r_II); int ret = 0, m = (s + t) >> 1; if (l_I <= m) ret = gmax(ret, Get_I(Son_I[x][0], s, m, l_I, r_I, l_II, r_II)); if (r_I >= m + 1) ret = gmax(ret, Get_I(Son_I[x][1], m + 1, t, l_I, r_I, l_II, r_II)); return ret;}int main(){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) { Read(E[i].Num); E[i].Pos = i; E[i].Prev = Last[E[i].Num]; E[E[i].Prev].Next = i; E[i].Next = n + 1; Last[E[i].Num] = i; } sort(E + 1, E + n + 1); for (int i = 1; i <= n; ++i) Insert_I(Root_I[i], Root_I[i - 1], 0, n + 1, E[i].Next, E[i].Pos, E[i].Num); Ans = 0; int x, y, l, r, p; for (int i = 1; i <= m; ++i) { Read(x); Read(y); l = gmin((x + Ans) % n + 1, (y + Ans) % n + 1); r = gmax((x + Ans) % n + 1, (y + Ans) % n + 1); p = lower_bound(E + 1, E + n + 1, l) - E - 1; Ans = Get_I(Root_I[p], 0, n + 1, r + 1, n + 1, l, r); printf("%d\n", Ans); } return 0;}

  

转载于:https://www.cnblogs.com/JoeFan/p/4428503.html

你可能感兴趣的文章
Flask 系列之 SQLAlchemy
查看>>
iframe跨域与session失效问题
查看>>
aboutMe
查看>>
【Debug】IAR在线调试时报错,Warning: Stack pointer is setup to incorrect alignmentStack,芯片使用STM32F103ZET6...
查看>>
一句话说清分布式锁,进程锁,线程锁
查看>>
Hash和Bloom Filter
查看>>
SQL Server获取月度列表
查看>>
python常用函数
查看>>
python 描点画圆
查看>>
FastDFS使用
查看>>
服务器解析请求的基本原理
查看>>
pycharm 如何设置方法调用字体颜色
查看>>
VUE源码解析心得
查看>>
数据结构
查看>>
Oracle数据库的启动与关闭
查看>>
gnome-shell 扩展
查看>>
DDD理论学习系列(9)-- 领域事件
查看>>
Java运行环境的配置(JDK和JRE)
查看>>
nodejs的优点
查看>>
SqlServer 跨库访问
查看>>