题解 P9993【[Ynoi Easy Round 2024] TEST_133】

发布时间 2023-12-27 13:35:11作者: rui_er

就硬把 线段树 3数列分块入门 2 揉到一起出。

维护原数组 \(a\) 及其历史最大值 \(hist\),对每个块,维护块内 \(a\) 升序排序后结果 \(p\)、块内 \(a\) 升序排序后历史最大值前缀和 \(prehist\)、块加标记 \(add\)、块历史和加标记 \(histadd\)

下传标记和区间修改操作仿照 线段树 3 维护即可,区间查询只需要散块暴力、整块二分。

时间复杂度 \(O((n+m)\sqrt{n}\log n)\)

// Problem: P9993 [Ynoi Easy Round 2024] TEST_133
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P9993
// Memory Limit: 512 MB
// Time Limit: 40000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x, y, z) for(int x = (y); x <= (z); ++x)
#define per(x, y, z) for(int x = (y); x >= (z); --x)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do {freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);} while(false)
#define endl '\n'
using namespace std;
typedef long long ll;

mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
int randint(int L, int R) {
    uniform_int_distribution<int> dist(L, R);
    return dist(rnd);
}

template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}

template<int mod>
inline unsigned int down(unsigned int x) {
	return x >= mod ? x - mod : x;
}

template<int mod>
struct Modint {
	unsigned int x;
	Modint() = default;
	Modint(unsigned int x) : x(x) {}
	friend istream& operator>>(istream& in, Modint& a) {return in >> a.x;}
	friend ostream& operator<<(ostream& out, Modint a) {return out << a.x;}
	friend Modint operator+(Modint a, Modint b) {return down<mod>(a.x + b.x);}
	friend Modint operator-(Modint a, Modint b) {return down<mod>(a.x - b.x + mod);}
	friend Modint operator*(Modint a, Modint b) {return 1ULL * a.x * b.x % mod;}
	friend Modint operator/(Modint a, Modint b) {return a * ~b;}
	friend Modint operator^(Modint a, int b) {Modint ans = 1; for(; b; b >>= 1, a *= a) if(b & 1) ans *= a; return ans;}
	friend Modint operator~(Modint a) {return a ^ (mod - 2);}
	friend Modint operator-(Modint a) {return down<mod>(mod - a.x);}
	friend Modint& operator+=(Modint& a, Modint b) {return a = a + b;}
	friend Modint& operator-=(Modint& a, Modint b) {return a = a - b;}
	friend Modint& operator*=(Modint& a, Modint b) {return a = a * b;}
	friend Modint& operator/=(Modint& a, Modint b) {return a = a / b;}
	friend Modint& operator^=(Modint& a, int b) {return a = a ^ b;}
	friend Modint& operator++(Modint& a) {return a += 1;}
	friend Modint operator++(Modint& a, int) {Modint x = a; a += 1; return x;}
	friend Modint& operator--(Modint& a) {return a -= 1;}
	friend Modint operator--(Modint& a, int) {Modint x = a; a -= 1; return x;}
	friend bool operator==(Modint a, Modint b) {return a.x == b.x;}
	friend bool operator!=(Modint a, Modint b) {return !(a == b);}
};

const int N = 5e5 + 5;
const ll inf = 0x3f3f3f3f3f3f3f3fll;

int n, m, B, cnt, L[N], R[N], pos[N], id[N];
ll a[N], p[N], hist[N], prehist[N], add[N], histadd[N];

inline void pushdown(int b) {
    rep(i, L[b], R[b]) {
        chkmax(hist[i], a[i] + histadd[b]);
        a[i] += add[b];
    }
    add[b] = histadd[b] = 0;
}

inline void rebuild(int b) {
    rep(i, L[b], R[b]) id[i] = i;
    sort(id + L[b], id + 1 + R[b], [&](int x, int y) {return a[x] < a[y];});
    rep(i, L[b], R[b]) p[i] = a[id[i]];
    prehist[L[b]] = hist[id[L[b]]];
    rep(i, L[b] + 1, R[b]) prehist[i] = max(prehist[i - 1], hist[id[i]]);
}

inline void build() {
    B = sqrt(n);
    chkmax(B, 1);
    chkmin(B, n);
    while(++cnt) {
        L[cnt] = R[cnt - 1] + 1;
        R[cnt] = min(B * cnt, n);
        rep(i, L[cnt], R[cnt]) pos[i] = cnt;
        rebuild(cnt);
        if(R[cnt] == n) break;
    }
}

inline void bruteModify(int l, int r, int k) {
    pushdown(pos[l]);
    rep(i, l, r) {
        a[i] += k;
        chkmax(hist[i], a[i]);
    }
    rebuild(pos[l]);
}

inline void modify(int l, int r, int k) {
    if(pos[l] == pos[r]) bruteModify(l, r, k);
    else {
        bruteModify(l, R[pos[l]], k);
        rep(i, pos[l] + 1, pos[r] - 1) {
            add[i] += k;
            chkmax(histadd[i], add[i]);
        }
        bruteModify(L[pos[r]], r, k);
    }
}

inline ll bruteQuery(int l, int r, int k) {
    ll ans = -inf;
    rep(i, l, r) {
        if(a[i] + add[pos[i]] < k) {
            chkmax(ans, hist[i]);
            chkmax(ans, a[i] + histadd[pos[i]]);
        }
    }
    return ans;
}

inline ll query(int l, int r, int k) {
    if(pos[l] == pos[r]) return bruteQuery(l, r, k);
    else {
        ll ans = -inf;
        chkmax(ans, bruteQuery(l, R[pos[l]], k));
        rep(i, pos[l] + 1, pos[r] - 1) {
            ll* it = lower_bound(p + L[i], p + 1 + R[i], k - add[i]) - 1;
            if(p + L[i] <= it) {
                chkmax(ans, prehist[it - p]);
                chkmax(ans, (*it) + histadd[i]);
            }
        }
        chkmax(ans, bruteQuery(L[pos[r]], r, k));
        return ans;
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n >> m;
    rep(i, 1, n) cin >> a[i];
    rep(i, 1, n) hist[i] = a[i];
    build();
    while(m--) {
        int op, l, r, k;
        cin >> op >> l >> r >> k;
        if(op == 1) modify(l, r, k);
        else {
            ll ans = query(l, r, k);
            if(ans == -inf) cout << "-inf" << endl;
            else cout << ans << endl;
        }
    }
    return 0;
}