题意
一共有n件商品,编号为1~n,有两种操作。
M X Y
:在第X天会卖出编号为Y的商品。D X Y
:询问[1,X]
中卖出的商品编号>=Y
中编号最小的一个是哪个,没有的话输出-1
。
对于每个询问D,输出相应的答案。
数据范围1<=n<=2e5
,1 <=x<=1e9
。
题解
对商品建立一颗线段树,线段树的结点维护的是当前区间里最找卖出的时间。
对于一个查询,我们可以二分答案,即二分编号最小的物品,令l=Y, r = n
,然后二分答案,对于每个二分的mid
,如果[l,mid]
的中有符合<=X
的(在编号l,mid]
之间的物品里有小等于第X天卖出的物品),那么r = mid-1
,否则l=mid+1
。
时间复杂度为:O(nlognlogn)
,2e5*14*14 ≈ 4e7
代码
#include <bits/stdc++.h>
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
const int N = 200000 + 5;
const int INF = 0x7fffffff;
int n, q;
int val[N<<2];
void pushup(int rt) {
val[rt] = min(val[rt<<1], val[rt<<1|1]);
}
void update(int rt, int l, int r, int p, int v) {
if (l == r) {
val[rt] = v;
return;
}
int mid = (l + r) >> 1;
if (p <= mid) update(lson, p, v);
if (p > mid) update(rson, p, v);
pushup(rt);
}
int query(int rt, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return val[rt];
}
int mid = (l + r) >> 1;
int ret = INF;
if (ql <= mid) ret = min(ret, query(lson, ql, qr));
if (qr > mid) ret = min(ret, query(rson, ql, qr));
return ret;
}
int find(int l, int r, int lim) {
int ans = -1;
while (l <= r) {
// cout << l << " " << r << endl;
int mid = (l + r) >> 1;
if (query(1, 1, n, l, mid) <= lim) {
r = mid - 1;
ans = mid;
} else l = mid + 1;
}
return ans;
}
int main() {
freopen("sample.in", "r", stdin);
freopen("sample.out", "w", stdout);
scanf("%d%d", &n, &q);
char op[3];
int x, y;
memset(val, 0x7f, sizeof val);
for (int i = 1; i <= q; ++i) {
scanf("%s%d%d", op, &x, &y);
if (op[0] == 'M') update(1, 1, n, y, x);
if (op[0] == 'D') {
printf("%d\n", find(y, n, x));
}
}
return 0;
}