题意:
一个初始为空的序列,两种操作:
1)A x:将x加入序列尾
2)B x :查询序列中的一个数A[i], 使 A[i] mod p最小的情况下, i最大, 输出i
思路:
用线段树维护数值区间内的最小的数是多少。
1)对于较小的p可以直接暴力,由于数据较水可过。不过其实可以离线处理询问,对于较小的p每加一个数就更新其答案,p相同的询问就可以一起算了(然而懒得写)。
2)对于较大的p,在区间[0, p - 1], [p, p * 2 - 1] ......内查询最小值即可。由于本题的特性可在线段树的查询时进行一些优化(见代码)。
调了好久,后来发现划分区间查询时的一个细节写错了。。。。。。后来又发现输出写错了。。。。。。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define Set(i,j) memset(i, j, sizeof(i))
#define For(i,j,k) for(int i = j;i <= k;i++)
#define Forr(i,j,k) for(int i = j;i >= k;i--)
#define lc (h << 1)
#define rc (h << 1 | 1)
#define M ((L + R) >> 1)
using namespace std;
const int N = 500020, E = 40010;
int n, cnt, A[E], now[N];
struct Segment_Tree{
int Min[N<<2];
void init(){
Set(Min, 0x3f), Set(now, 0);
}
void update(int h, int L, int R, int pos){
Min[h] = min(Min[h], pos);
if(L == R) return;
if(pos <= M) update(lc, L, M, pos);
else update(rc, M+1, R, pos);
}
int query(int h, int L, int R, int l, int r){
if(Min[h] > 1e8 || (l <= L && r >= R)) return Min[h];
int ret = 2e9;
if(l <= M) ret = query(lc, L, M, l, r); if(ret <= N) return ret;
if(r > M) ret = query(rc, M+1, R, l, r);
return ret;
}
}Tree;
int Read(){
char c = getchar();
for(;c > '9' || c < '0';c = getchar());
int x = c - '0';
for(c = getchar();c >= '0' && c <= '9';c = getchar()) x = x * 10 + c - '0';
return x;
}
void Solve1(int p){
int Ans = -1, Min = 2e9;
Forr(i,cnt,1){
if(A[i] % p < Min) Min = A[i] % p, Ans = i;
if(!Min) break;
}
printf("%d\n", Ans);
}
void Solve2(int p){
int Ans = 1e9, pos = 1e9;
For(i,0,N/p){
int t = Tree.query(1, 0, N, i * p, min(N, (i + 1) * p - 1));
if(t <= N && t - i * p < Ans) Ans = t - i * p, pos = now[t];
else if(t <= N && t - i * p == Ans) pos = max(pos, now[t]);
}
printf("%d\n", pos);
}
int main(){
int CASE = 0;
while(scanf("%d", &n) && n){
if(CASE) puts("");
printf("Case %d:\n", ++CASE);
Tree.init();
cnt = 0;
while(n--){
char Q[5];
scanf("%s", Q);
int x = Read();
if(Q[0] == 'B'){
Tree.update(1, 0, N, x);
A[++cnt] = x;
now[x] = cnt;
}
else{
if(!cnt){
puts("-1");
continue;
}
if(x <= 3000) Solve1(x);
else Solve2(x);
}
}
}
return 0;
}