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的更多相关文章

  1. BZOJ 3489 A simple rmq problem ——KD-Tree

    考前写写板子. 用$(i,pre[i],nxt[i])$来描述一个点,然后就变成了区间求最值的问题. KD-Tree 由低维转向高维的方法,可以用来敲暴力. 剩下就是KD-Tree的基本操作了. #i ...

  2. BZOJ 3489: A simple rmq problem (KD-tree做法)

    KD树水过这道可持久化树套树-其实就是个三维偏序 题解戳这里 CODE #include <bits/stdc++.h> using namespace std; #define ls ( ...

  3. BZOJ 3489: A simple rmq problem

    3489: A simple rmq problem Time Limit: 40 Sec  Memory Limit: 600 MBSubmit: 1594  Solved: 520[Submit] ...

  4. 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][ ...

  5. [BZOJ 3489] A simple rmq problem 【可持久化树套树】

    题目链接:BZOJ - 3489 题目分析 “因为是OJ上的题,就简单点好了.”——出题人 真的..好..简单... 首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有 ...

  6. BZOJ 3489 A simple rmq problem 可持久化KDtree/二维线段树

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题意概述: 给出一个序列,每次询问一个序列区间中仅出现了一次的数字最大是多少,如果 ...

  7. bzoj 3489 A simple rmq problem - 线段树

    Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直 ...

  8. bzoj 3489 A simple rmq problem——主席树套线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题解:http://www.itdaan.com/blog/2017/11/24/9b ...

  9. BZOJ 3489 A simple rmq problem(可持久化线段树)

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3489 题意:一个数列.每次询问一个区间内出现一次的最大的数字是多少. 思路:设la ...

随机推荐

  1. H5端调起百度地图、腾讯地图app

    来自一个需求的总结: 在微信公众号中根据地图上的marker和label,或者搜索结果点击调起地图APP进行导航. 一开始是使用百度地图进行开发,后面转腾讯是因为微信不允许不是自家或者合作方的APP在 ...

  2. LeetCode 160. Intersection of Two Linked Lists (两个链表的交点)

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  3. Hadoop Yarn(一)—— 单机伪分布式环境安装

    HamaWhite(QQ:530422429)原创作品,转载请注明出处:http://write.blog.csdn.net/postedit/40556267. 本文是依据Hadoop官网安装教程写 ...

  4. HDU 5489 Difference of Clustering 图论

    Difference of Clustering Problem Description Given two clustering algorithms, the old and the new, y ...

  5. 【Ubuntu】某灯图标过大

    发现某灯在桌面上图标过大,点击resize拖动没反应,遂查找原因 发现是它图标只有128x128的版本,所以显得比别的图标大 打开lantern.desktop(不知道.desktop请看https: ...

  6. docker run Influxdb

    本文假设读者已经安装并配置好了Docker的运行环境,Docker daemon已经运行.如果要在Suse上安装Docker,请参考文章Docker学习系列1-Suse安装Docker来设置Docke ...

  7. 【HAOI 2008】 糖果传递

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1045 [算法] 环形均分纸牌问题 [代码] #include<bits/std ...

  8. 【高德地图API】Pivot控件中加载地图并禁止Pivot手势

    如题,解决方案,参考[Windows phone应用开发[20]-禁止Pivot手势]http://www.cnblogs.com/chenkai/p/3408658.html. xaml代码清单   ...

  9. 【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)

    题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...

  10. Wannafly挑战赛19 A-队列Q

    题目描述 ZZT 创造了一个队列 Q.这个队列包含了 N 个元素,队列中的第 i 个元素用 Qi 表示.Q1 表示队头元素,QN 表示队尾元素.队列中的元素是 N 的一个全排列. ZZT 需要在这个队 ...