WHU网络赛store 线段树+二分

题意

一共有n件商品,编号为1~n,有两种操作。

  1. M X Y:在第X天会卖出编号为Y的商品。
  2. 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 

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

你可能感兴趣的:(二分,线段树)