题解 BZOJ 3489 A simple rmq problem

给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数
强制在线。

设$p[i]$为$a[i]$上一次出现位置,$q[i]$为$a[i]$下一次出现位置。

每次查询的就是
$ max _{l<=i<=r} a[i] $ 且$q[i] >r$ , $p[i]< l $。

可以排序然后树套树做。

偷懒写了KD-TREE。。复杂度$O(n^{5/3})$,不强制在线的话可以做到$O(n^{3/2})$ 。

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int ans;
int a[100005],last[100005],p[100005],q[100005];
struct Point{
int x[3],w;
}P[100005];
int D;
int root;
int ls[100005],rs[100005];
int mn[100005][3],mx[100005][3];
int w[100005];
bool cmp(Point a,Point b){
return a.x[D]<b.x[D];
}
int mk(int l,int r){
if(l>r) return 0;
int mid=(l+r)>>1;
int dd=(D+1)%3;
nth_element(P+l,P+mid,P+r+1,cmp);
for(int i=0;i<3;i++) mn[mid][i]=mx[mid][i]=P[mid].x[i];
w[mid]=P[mid].w;
D=dd;
ls[mid]=mk(l,mid-1);
D=dd;
rs[mid]=mk(mid+1,r);
if(ls[mid]){
for(int i=0;i<3;i++){
mn[mid][i]=min(mn[mid][i],mn[ls[mid]][i]);
mx[mid][i]=max(mx[mid][i],mx[ls[mid]][i]);
}
w[mid]=max(w[mid],w[ls[mid]]);
}
if(rs[mid]){
for(int i=0;i<3;i++){
mn[mid][i]=min(mn[mid][i],mn[rs[mid]][i]);
mx[mid][i]=max(mx[mid][i],mx[rs[mid]][i]);
}
w[mid]=max(w[mid],w[rs[mid]]);
}
return mid;
}
int pos[3][2];//0 mn 1 mx
bool judge(int o){
for(int i=0;i<3;i++){
if(pos[i][0]>mx[o][i]) return 0;
if(pos[i][1]<mn[o][i]) return 0;
}
return 1;
}
void ask(int o){
bool ok=1;
for(int i=0;i<3&&ok;i++){
if(mn[o][i]<pos[i][0]) ok=0;
if(mx[o][i]>pos[i][1]) ok=0;
}
if(ok){
ans=max(ans,w[o]);
}else{
ok=1;
for(int i=0;i<3&&ok;i++){
if(P[o].x[i]<pos[i][0]) ok=0;
if(P[o].x[i]>pos[i][1]) ok=0;
}
if(ok) ans=max(ans,P[o].w);
if(ls[o]&&judge(ls[o])){
ask(ls[o]);
}
if(rs[o]&&judge(rs[o])){
ask(rs[o]);
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) p[i]=last[a[i]],last[a[i]]=i;
for(int i=1;i<=n;i++) last[i]=n+1;
for(int i=n;i>=1;i--) q[i]=last[a[i]],last[a[i]]=i;
for(int i=1;i<=n;i++) P[i].x[0]=i,P[i].x[1]=p[i],P[i].x[2]=q[i],P[i].w=a[i];
D=0;
root=mk(1,n);
int l,r;
while(m--){
scanf("%d%d",&l,&r);
l=(l+ans)%n+1;
r=(r+ans)%n+1;
if(l>r) swap(l,r);
ans=0;
pos[0][0]=l;pos[0][1]=r;
pos[1][0]=0;pos[1][1]=l-1;
pos[2][0]=r+1;pos[2][1]=n+1;
D=0;
ask(root);
printf("%d\n",ans);
}
return 0;
}

评论小助手

评论正在加载...

Tip: 点击下方链接切换到 Disqus 评论框可以获得邮件提醒哦
🗣️ 加载 Disqus 评论框