POJ 3145 线段树

来源:互联网 发布:怎么注册国外域名 编辑:程序博客网 时间:2024/06/10 07:30

题意:

    一个初始为空的序列,两种操作:

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




1 0
原创粉丝点击