• LibreOJ #6279


    题目链接:#6279. 数列分块入门 3

    题目大意

    给出一个长为 (n) 的数列,以及 (n) 个操作,操作涉及区间加法,询问区间内小于某个值 (x) 的前驱(比其小的最大元素)。

    solution

    这就是标准的分块套平衡树的裸题

    但是平衡树太难写了,这里我们就对每个块排个序就好了

    我们还是沿用第二题的写法

    然后,查询就变成了找最大值,同时记录一下个数,如果这个个数为0, 那就是-1, 否则就是我们找的值

    注意:在 (lower_bound) 时, 最后的最大值别忘了加上我们记录的值哟

    Code:

    /**
    *    Author: Alieme
    *    Data: 2020.9.8
    *    Problem: LibreOJ #6279
    *    Time: O()
    */
    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    
    #define int long long
    #define rr register
    
    #define inf 1e12
    #define MAXN 100010
    
    using namespace std;
    
    inline int read() {
    	int s = 0, f = 0;
    	char ch = getchar();
    	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
    	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    void print(int x) {
    	if (x < 0) putchar('-'), x = -x;
    	if (x > 9) print(x / 10);
    	putchar(x % 10 + 48);
    }
    
    int n, len;
    
    int a[MAXN], b[MAXN], id[MAXN], v[MAXN];
    
    inline void update(int x) {
    	int l = (x - 1) * len + 1, r = min(x * len, n);
    	for (rr int i = l; i <= r; i++) b[i] = a[i];
    	sort(b + l, b + r + 1);
    }
    
    inline void add(int l, int r, int x) {
    	int start = id[l], end = id[r];
    	if (start == end) {
    		for (rr int i = l; i <= r; i++) a[i] += x;
    		update(id[l]);
    		return ;
    	}
    	for (rr int i = l; id[i] == start; i++) a[i] += x; update(start);
    	for (rr int i = start + 1; i < end; i++) v[i] += x;
    	for (rr int i = r; id[i] == end; i--) a[i] += x; update(end);
    }
    
    inline int fin(int pid, int x, int &ans) {
    	int l = (pid - 1) * len + 1, r = min(pid * len, n);
    	int t = lower_bound(b + l, b + r + 1, x - v[pid]) - (b + l);
    	ans += t;
    	// cout << t;
    	// cout << t << " " << b[t + l - 1] << " "  << x - v[pid] << "
    ";
    	if (t == 0) return -inf;
    	return b[t - 1 + l] + v[pid];
    }
    
    inline int query(int l, int r, int x) {
    	int maxx = -inf, ans = 0, start = id[l], end = id[r];
    	if (start == end) {
    		for (rr int i = l; i <= r; i++) if (a[i] + v[start] < x) maxx = max(maxx, a[i] + v[start]), ans++;
    		if (ans == 0) maxx = -1;
    		return maxx;
    	}
    	for (rr int i = l; id[i] == start; i++) if (a[i] + v[start] < x) maxx = max(maxx, a[i] + v[start]), ans++;
    	for (rr int i = start + 1; i < end; i++) maxx = max(maxx, fin(i, x, ans));
    	for (rr int i = r; id[i] == end; i--) if (a[i] + v[end] < x) maxx = max(maxx, a[i] + v[end]), ans++;
    	if (ans == 0) maxx = -1;
    	return maxx;
    }
    
    signed main() {
    	// freopen("a1.in", "r", stdin);
    	// freopen("a.out", "w", stdout);
    	n = read(); 
    	len = sqrt(n);
    	for (rr int i = 1; i <= n; i++) a[i] = read(), id[i] = (i - 1) / len + 1;
    	for (rr int i = len; i <= n; i += len) update(id[i]);
    	for (rr int i = 1; i <= n; i++) {
    		int opt = read(), l = read(), r = read(), c = read();
    		if (opt == 0) add(l, r, c);
    		if (opt == 1) cout << query(l, r, c) << "
    ";
    	}
    }
    
    
  • 相关阅读:
    二叉搜索树与双向链表
    TCP 三次握手与四次挥手
    复杂链表的复制
    二叉树中和为某一值的路径
    二叉搜索树的后序遍历序列
    从上往下打印二叉树
    栈的压入、弹出序列
    jenkins 持续集成和交付——一个构件小栗子前置(三)
    jenkins 持续集成和交付——gogs安装(外篇)
    jenkins 持续集成和交付——安装与账户安全还有凭证(二)
  • 原文地址:https://www.cnblogs.com/lieberdq/p/13641823.html
Copyright © 2020-2023  润新知