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$ 本身,第三维维护下一次出现的位置.
每次按照上述条件直接进行数点即可.
思路还是非常巧妙的.
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; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步