BZOJ 3489: A simple rmq problem KDtree
Description
因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。
Input
第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)
第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N
再下面M行,每行两个整数x,y,
询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<):
l=min((x+lastans)mod n+1,(y+lastans)mod n+1);
r=max((x+lastans)mod n+1,(y+lastans)mod n+1);
Lastans表示上一个询问的答案,一开始lastans为0
Output
一共M行,每行给出每个询问的答案。
题解: 对于一个区间 $[l,r]$ 一个数只出现依次说明上次出现在 $[1,l-1]$ 中(或没出现),下一次出现在 $[r+1,n]$ 中(或没出现).
直接维护一个 3 维 $KDtree$ 即可.
第一维维护 $pre_{i}$,第二位维护 $i$ 本身,第三维维护下一次出现的位置.
每次按照上述条件直接进行数点即可.
思路还是非常巧妙的.
#include<bits/stdc++.h>
#define maxn 200000
#define inf 100000000
#define mid ((l+r)>>1)
#define lson (t[x].ch[0])
#define rson (t[x].ch[1])
using namespace std;
void setIO(string s)
{
string in=s+".in";
freopen(in.c_str(),"r",stdin);
}
int n,Q,lastans,d,_ans;
int lst[maxn],nex[maxn],pos[maxn],arr[maxn];
struct Node
{
int ch[2],minv[3],maxv[3],p[3],w,_max;
}t[maxn];
bool cmp(Node a,Node b)
{
if(a.p[d]==b.p[d] && a.p[(d+1)%3]==b.p[(d+1)%3]) return a.p[(d+2)%3] < b.p[(d+2)%3];
if(a.p[d]==b.p[d]) return a.p[(d+1)%3] < b.p[(d+1)%3];
return a.p[d] < b.p[d];
}
void pushup(int x,int y)
{
for(int i=0;i<3;++i)
{
t[x].minv[i]=min(t[x].minv[i],t[y].minv[i]);
t[x].maxv[i]=max(t[x].maxv[i],t[y].maxv[i]);
}
t[x]._max=max(t[x]._max,t[y]._max);
}
int build(int l,int r,int o)
{
d=o;
nth_element(t+l,t+mid,t+1+r,cmp);
for(int i=0;i<3;++i) t[mid].minv[i]=t[mid].maxv[i]=t[mid].p[i];
t[mid].ch[0]=t[mid].ch[1]=0;
t[mid]._max=t[mid].w;
if(mid>l)
{
t[mid].ch[0]=build(l,mid-1,(o+1)%3);
pushup(mid,t[mid].ch[0]);
}
if(r>mid)
{
t[mid].ch[1]=build(mid+1,r,(o+1)%3);
pushup(mid,t[mid].ch[1]);
}
return mid;
}
int isout(int x,int l,int r)
{
if(t[x].minv[0] >= l || t[x].maxv[2] <= r || t[x].minv[1] > r || t[x].maxv[1] < l) return 1;
return 0;
}
int isin(int x,int l,int r)
{
if(t[x].maxv[0] < l && t[x].minv[2] > r && t[x].minv[1] >= l && t[x].maxv[1] <= r) return 1;
return 0;
}
void query(int x,int l,int r)
{
if(isout(x, l, r)) return;
if(isin(x, l, r))
{
_ans=max(_ans, t[x]._max);
return;
}
if(t[x].p[0] < l && t[x].p[1] >= l && t[x].p[1] <= r && t[x].p[2] > r) _ans=max(_ans, t[x].w);
if(lson && t[lson]._max > _ans) query(lson, l, r);
if(rson && t[rson]._max > _ans) query(rson, l, r);
}
int main()
{
int i,j,x,y,root,a;
// setIO("input");
scanf("%d%d",&n,&Q);
for(i=1;i<=n;++i)
{
scanf("%d",&a);
nex[pos[a]]=i, lst[i]=pos[a], pos[a]=i, arr[i]=a;
}
for(i=1;i<=n;++i)
{
t[i].p[0]=lst[i], t[i].p[1]=i, t[i].p[2] = nex[i] ? nex[i] : n + 1, t[i].w=arr[i];
}
root=build(1,n,0);
while(Q--)
{
scanf("%d%d",&x,&y);
x=(x+lastans) % n + 1;
y=(y+lastans) % n + 1;
if(x > y) swap(x, y);
_ans = -inf;
query(root, x, y);
lastans = (_ans == -inf ? 0 : _ans);
printf("%d\n",lastans);
}
return 0;
}
BZOJ 3489: A simple rmq problem KDtree的更多相关文章
- BZOJ 3489 A simple rmq problem ——KD-Tree
考前写写板子. 用$(i,pre[i],nxt[i])$来描述一个点,然后就变成了区间求最值的问题. KD-Tree 由低维转向高维的方法,可以用来敲暴力. 剩下就是KD-Tree的基本操作了. #i ...
- BZOJ 3489: A simple rmq problem (KD-tree做法)
KD树水过这道可持久化树套树-其实就是个三维偏序 题解戳这里 CODE #include <bits/stdc++.h> using namespace std; #define ls ( ...
- BZOJ 3489: A simple rmq problem
3489: A simple rmq problem Time Limit: 40 Sec Memory Limit: 600 MBSubmit: 1594 Solved: 520[Submit] ...
- bzoj 3489: A simple rmq problem k-d树思想大暴力
3489: A simple rmq problem Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 551 Solved: 170[Submit][ ...
- [BZOJ 3489] A simple rmq problem 【可持久化树套树】
题目链接:BZOJ - 3489 题目分析 “因为是OJ上的题,就简单点好了.”——出题人 真的..好..简单... 首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有 ...
- BZOJ 3489 A simple rmq problem 可持久化KDtree/二维线段树
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题意概述: 给出一个序列,每次询问一个序列区间中仅出现了一次的数字最大是多少,如果 ...
- bzoj 3489 A simple rmq problem - 线段树
Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直 ...
- bzoj 3489 A simple rmq problem——主席树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题解:http://www.itdaan.com/blog/2017/11/24/9b ...
- BZOJ 3489 A simple rmq problem(可持久化线段树)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3489 题意:一个数列.每次询问一个区间内出现一次的最大的数字是多少. 思路:设la ...
随机推荐
- [Vue @Component] Pass Props to Vue Functional Templates
Functional templates allow you to create components consisting of only the template tag and exposing ...
- C++与C的那些差异
虽说C++是向后兼容C的,但C++与C还是存在许多差异.这里举了几个例子,也是我们很容易忽略的地方.如果你还知道其他的更多的Differences,或者发现什么错误,可以评论告诉我,大家一起学习进步. ...
- objc_setAssociatedObject
学习笔记:通过 objc_setAssociatedObject alert 和 button关联 及传值 标签: ios 2013-11-22 16:25 7924人阅读 评论(1) 收藏 举报 ...
- jstl自己定义函数的使用
因为本人之前并没有接触过jstl标签,说来也可笑,之前一直使用struts2标签.近期项目用到jstl,所以做些记录方便以后自己查看. jstl的强大原因之中的一个我觉得就是他的自己定义函数,我们能够 ...
- SVN提交代码冲突解决方法总结
在近期svn提交代码时遇到多种情况的问题,现做一个解决办法的总结如下: 插播一条:idea下被svn版本控制各类文件的颜色区分,红棕色,未加入版本控制:绿色,已经加入控制暂未提交:蓝色,加入,已提交, ...
- ios dyld: Library not loaded: @rpath/xxx.framework/xxx 之根本原因
碰到问题 dyld: Library not loaded: @rpath/xxx.framework/xxx Referenced from: /var/containers/Bundle/Appl ...
- 5.3.3 deque对象
class collections.deque([iterable[, maxlen]]) 返回一个新双向队列,当有输入迭代器时.会从左至右地加入到队列里.假设没有输入參数,就创建一个空队列. deq ...
- TGraphicControl和TCustomControl自绘过程的理论解释
TGraphicControl = class(TControl) // 这个类实在是简单,因为所有事情都已经委托给它的父Win控件了,只要管自己即可 private FCanvas: TCanvas ...
- hdu 4888 Redraw Beautiful Drawings(最大流,判环)
pid=4888">http://acm.hdu.edu.cn/showproblem.php?pid=4888 加入一个源点与汇点,建图例如以下: 1. 源点 -> 每一行相应 ...
- protected (C# Reference)
https://msdn.microsoft.com/en-us/library/bcd5672a.aspx The protected keyword is a member access modi ...