BZOJ 3489: A simple rmq problem

3489: A simple rmq problem

Time Limit: 40 Sec  Memory Limit: 600 MB
Submit: 1594  Solved: 520
[Submit][Status][Discuss]

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行,每行给出每个询问的答案。

 

Sample Input

10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9

Sample Output

4
10
10
0
0
10
0
4
0
4

HINT

 



注意出题人为了方便,input的第二行最后多了个空格。


2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测


 

 

Source

[ Submit][ Status][ Discuss]

 

参考了网上的一些做法,可持久化树套树什么的实在吃不消,于是采用了KD-Tree的方法。

考虑一个点,在哪个区间内它是唯一出现的呢?

设prev[i]为上一个和i处权值相同的位置,next[i]为下一个和i处权值相同的位置,显然在(prev[i],next[i])这个区间内,i点是该权值唯一出现的位置。

对于一个询问(ql,qr),我们可以转换为:找出满足 prev[i] < ql 且 next[i] > qr 且 ql <= i <= qr 的i中,权值最大的i。这个就是KD-Tree维护三维的区间最值问题。

 

  1 #include <bits/stdc++.h>
  2 
  3 inline int getC(void) {
  4     static const int siz = 1024;
  5     
  6     static char buf[siz];
  7     static char *hd = buf + siz;
  8     static char *tl = buf + siz;
  9     
 10     if (hd == tl)
 11         fread(hd = buf, 1, siz, stdin);
 12     
 13     return int(*hd++);
 14 }
 15 
 16 inline int getI(void) {
 17     register int ret = 0;
 18     register int neg = false;
 19     register int bit = getC();
 20     
 21     for (; bit < 48; bit = getC())
 22         if (bit == '-')neg ^= true;
 23 
 24     for (; bit > 47; bit = getC())
 25         ret = ret * 10 + bit - '0';
 26     
 27     return neg ? -ret : ret;
 28 }
 29 
 30 template <class T>
 31 inline T min(const T &a, const T &b) {
 32     return a < b ? a : b;
 33 }
 34 
 35 template <class T>
 36 inline T max(const T &a, const T &b) {
 37     return a > b ? a : b;
 38 }
 39 
 40 const int maxn = 100005;
 41 
 42 int n, m;
 43 int answer;
 44 int num[maxn];
 45 
 46 int next[maxn];
 47 int prev[maxn];
 48 int last[maxn];
 49 
 50 int value[maxn][3];
 51 
 52 int pos[maxn];
 53 int maxv[maxn];
 54 int lson[maxn];
 55 int rson[maxn];
 56 int mini[maxn][3];
 57 int maxi[maxn][3];
 58 
 59 int qryL, qryR;
 60 
 61 int cmpK;
 62 
 63 inline bool cmp(const int &a, const int &b) {
 64     return value[a][cmpK] < value[b][cmpK];
 65 }
 66 
 67 int build(int l, int r, int k) {
 68     int mid = (l + r) >> 1; cmpK = k;
 69     std::nth_element(
 70        pos + l, pos + mid, pos + r + 1, cmp);
 71     maxv[mid] = num[pos[mid]];
 72     for (int i = 0; i < 3; ++i)
 73         mini[mid][i] = maxi[mid][i] = value[pos[mid]][i];
 74     if (l < mid) {
 75         lson[mid] = build(l, mid - 1, (k + 1) % 3);
 76         maxv[mid] = max(maxv[mid], maxv[lson[mid]]);
 77         for (int i = 0; i < 3; ++i) {
 78             mini[mid][i] = min(mini[mid][i], mini[lson[mid]][i]);
 79             maxi[mid][i] = max(maxi[mid][i], maxi[lson[mid]][i]);
 80         }
 81     }
 82     if (r > mid) {
 83         rson[mid] = build(mid + 1, r, (k + 1) % 3);
 84         maxv[mid] = max(maxv[mid], maxv[rson[mid]]);
 85         for (int i = 0; i < 3; ++i) {
 86             mini[mid][i] = min(mini[mid][i], mini[rson[mid]][i]);
 87             maxi[mid][i] = max(maxi[mid][i], maxi[rson[mid]][i]);
 88         }
 89     }
 90     return mid;
 91 }
 92 
 93 inline bool check(int t) {
 94     if (mini[t][0] >  qryR || maxi[t][0] <  qryL)return false;
 95     if (mini[t][1] >= qryL || maxi[t][2] <= qryR)return false;
 96     return true;
 97 }
 98 
 99 void query(int t) {
100     if (mini[t][0] >= qryL && maxi[t][0] <= qryR && maxi[t][1] < qryL && mini[t][2] > qryR)
101         { answer = max(answer, maxv[t]); return; }
102     if (pos[t] >= qryL && pos[t] <= qryR && prev[pos[t]] < qryL && next[pos[t]] > qryR)
103         answer = max(answer, num[pos[t]]);
104     if (maxv[lson[t]] > maxv[rson[t]]) {
105         if (lson[t] && maxv[lson[t]] > answer && check(lson[t]))query(lson[t]);
106         if (rson[t] && maxv[rson[t]] > answer && check(rson[t]))query(rson[t]);
107     }
108     else {
109         if (rson[t] && maxv[rson[t]] > answer && check(rson[t]))query(rson[t]);
110         if (lson[t] && maxv[lson[t]] > answer && check(lson[t]))query(lson[t]);
111     }
112 }
113 
114 signed main(void) {
115     n = getI();
116     m = getI();
117     
118     for (int i = 1; i <= n; ++i)
119         num[i] = getI();
120         
121     for (int i = 1; i <= n; ++i)
122         last[i] = 0;
123         
124     for (int i = 1; i <= n; ++i)
125         prev[i] = last[num[i]], last[num[i]] = i;
126         
127     for (int i = n; i >= 1; --i)
128         last[i] = n + 1;
129     
130     for (int i = n; i >= 1; --i)
131         next[i] = last[num[i]], last[num[i]] = i;
132         
133     for (int i = 1; i <= n; ++i) {
134         pos[i] = i;
135         value[i][0] = i;
136         value[i][1] = prev[i];
137         value[i][2] = next[i];
138     }
139         
140     int root = build(1, n, 0);
141     
142     for (int i = 1; i <= m; ++i) {
143         int x = getI();
144         int y = getI();
145         qryL = (x + answer) % n + 1;
146         qryR = (y + answer) % n + 1;
147         if (qryL > qryR)
148             qryL ^= (qryR ^= (qryL ^= qryR));
149         answer = 0; query(root); printf("%d\n", answer);
150     }
151 }

 

@Author: YouSiki

 

转载于:https://www.cnblogs.com/yousiki/p/6242135.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值