买房
ps:和今年多校的某道题很像,只不过修改是永久的。正解没想出来,用线段树暴力搞出来的,5960ms。考虑线段树的节点维护两个信息:该区间的最大值,该区间以第一个元素为起点递增的最长序列的长度。那么问题在于每次更新后,怎么维护整个区间的递增序列长度(L),有一个很明显的想法,就是讨论左儿子和右儿子的最大值,如果左儿子的最大值大于右儿子的最大值,那么L = 左儿子的L,否则,就在右儿子所管辖的区间中找以左儿子的最大值为起点的最长递增序列,然后拼接一下就得到的整个区间的L。
inline void upd(int &x, int y) { x < y && (x = y); } const int N = 100005; int n, m, sum[4 * N]; double a[4 * N], Max[4 * N]; int Find(int l, int r, int root, double x) { if (l == r) { return 1; } int mid = (l + r) >> 1; if (Max[lson] <= x) return Find(mid + 1, r, rson, x); return sum[root] - sum[lson] + Find(l, mid, lson, x); } void Pushup(int l, int r, int root) { if (Max[lson] >= Max[rson]) { sum[root] = sum[lson]; } else { int mid = (l + r) >> 1; sum[root] = sum[lson] + Find(mid + 1, r, rson, Max[lson]); } Max[root] = max(Max[lson], Max[rson]); } void Update(int l, int r, int root, int pos, double x) { if (l == r) { a[root] = Max[root] = x; sum[root] = 1; return; } int mid = (l + r) >> 1; if (mid >= pos) Update(l, mid, lson, pos, x); else Update(mid + 1, r, rson, pos, x); Pushup(l, r, root); } int main() { BEGIN() { cin >> n >> m; mem(sum, 0); rep(i, 0, 4 * N) Max[i] = 0; Rep(i, 1, m) { int x, y; sc(x), sc(y); Update(1, n, 1, x, 1.0 * y / x); pr(sum[1]); } } return 0; }