【题解】BZOJ3489 A Hard RMQ problem(主席树套主席树)
【题解】A simple RMQ problem
占坑,免得咕咕咕了,争取在2h内写出代码
upd:由于博主太菜而且硬是要用指针写两个主席树,所以延后2hQAQ
upd:由于博主太菜而且太懒所以他决定写kd tree了
upd:由于博主太菜而且太懒所以他不写代码了(实际上是写了6k之后崩溃了)
所以直接口胡题解
题目大意:
因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。
好就是这样
解法:
我本来是想直接对值域线段树可持久化,然后类似于吉司机线段树一样维护最小值和次小值...发现不会查一个区间,于是我们可以这样:
每个位置记录i一个上一次出现的\(pre\)和下一次出现的\(next\),把所有数先按照\(pre\)从小往大排序,对于每一个位置,维护一个数组,数组的下标是next[i],数组里面的值是data[i],查询的时候查询查询这个数组\([r+1,n+1]\)中的最大值是多少,就是我们的答案。可持久化数组可以用主席树维护,前缀\(pre\)的\(next\)可以用主席树维护,所以只要主席树套主席树就\(ok\)了。
时空复杂度\(O(n \log^2 n)\)
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
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;
}
【题解】BZOJ3489 A Hard RMQ problem(主席树套主席树)的更多相关文章
- bzoj3489: A simple rmq problem (主席树)
//========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/ 转载要声明! //=============== ...
- BZOJ3489 A simple rmq problem 【可持久化树套树】*
BZOJ3489 A simple rmq problem Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一 ...
- dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448
4448: [Scoi2015]情报传递 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 588 Solved: 308[Submit][Status ...
- 【题解】P4585 [FJOI2015]火星商店问题(线段树套Trie树)
[题解]P4585 [FJOI2015]火星商店问题(线段树套Trie树) 语文没学好不要写省选题面!!!! 题目大意: 有\(n\)个集合,每个集合有个任意时刻都可用的初始元素.现在有\(m\)个操 ...
- BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)
题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...
- ZJOI 2017 树状数组(线段树套线段树)
题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r ...
- 【bzoj3217】ALOEXT 替罪羊树套Trie树
题目描述 taorunz平时最喜欢的东西就是可移动存储器了……只要看到别人的可移动存储器,他总是用尽一切办法把它里面的东西弄到手. 突然有一天,taorunz来到了一个密室,里面放着一排可移动存储器, ...
- 【bzoj4785】[Zjoi2017]树状数组 线段树套线段树
题目描述 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作 ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
随机推荐
- js遮罩层弹出显示效果组件化
1.在web开发中经常遇到遮罩层的效果,可以将这种常用方法通用化 function showid(idname){ var isIE = (document.all) ? true : false; ...
- 20180113Go匿名函数和闭包
最近codereview看到闭包,得学习下 https://studygolang.com/articles/5057 匿名函数:没有函数名的函数 闭包:外部函数定义的内部函数. 闭包给访问外部函数定 ...
- ubuntu 12.04上安装emacs24
1.如果安装了emacs23的先删掉 sudo apt-get purge emacs23 2.默认的软件源中没有emacs24,需要添加新源 sudo add-apt-repository ppa: ...
- Atitit.获得向上向下左的右的邻居的方法 软键盘的设计..
Atitit.获得向上向下左的右的邻居的方法 软键盘的设计.. Left right可以直接使用next prev.. Up down可以使用pix 判断...获得next element的posit ...
- Atitit.atiDataStoreService v2 新特性
Atitit.atiDataStoreService v2 新特性 1.1. V1 基础实现1 1.2. V2 增加了对 $uuid $cur_uid参数的支持1 1.3. 增加了fld ...
- PILE读书笔记_进程环境
进程是操作系统运行程序的一个实例, 也是操作系统分配资源的单位. 在Linux环境中, 每个进程都有独立的进程空间, 以便对不同的进程进行隔离, 使之不会互相影响. atexit函数 #include ...
- 使用Crypto++库的CBC模式实现加密
//***************************************************************************** //@File Name : scsae ...
- MAC下一些常用的命令行
统计了一下工作中一些会常用到的简单命令,加强记忆 ls 查看当前终端目录下面的文件 ls -a "ls -a"会出现一些带.xxxx的文 ...
- Redis 哈希槽
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余 ...
- OC 基础语法
:Obect c 与 c 语言的区别 () 后缀名不一样,C语言是.c 结尾 ,OC 是 .h结尾. () 输出信息不同 C语言是用print() 输出,OC 是用NSLog输出. () NSLog会 ...