BZOJ 3489: A simple rmq problem KDtree

Description

因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。

 

 

Input

第一行为两个整数N,MM是询问数,N是序列的长度(N<=100000M<=200000)

第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N

再下面M行,每行两个整数xy

询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<)

l=min(x+lastans)mod n+1,(y+lastansmod n+1);

r=max(x+lastans)mod n+1,(y+lastansmod n+1);

Lastans表示上一个询问的答案,一开始lastans0

 

Output

一共M行,每行给出每个询问的答案。

 题解: 对于一个区间 $[l,r]$ 一个数只出现依次说明上次出现在 $[1,l-1]$ 中(或没出现),下一次出现在 $[r+1,n]$ 中(或没出现).
直接维护一个 3 维 $KDtree$ 即可.
第一维维护 $pre_{i}$,第二位维护 $i$ 本身,第三维维护下一次出现的位置.
每次按照上述条件直接进行数点即可.
思路还是非常巧妙的.  

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
102
#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;
}

  

posted @   EM-LGH  阅读(195)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示