题意:如标题所示,给出N个数,以及M次查询,查询[L, R]区间内连续和小于等于U的最大值。
思路:很明显的,想到了一个做法,我们可以去对于U值作为一个时间刻度,进行升序,同时,一共有N * (N + 1) / 2个连续和,发现这么多连续和,其实不算多啊,我们对于每个连续和的权值存下来,并且维护它对应的L和R点,于是乎,我们实际上就将问题变成了求解二维区间(L, L)至二维区间(R, R)中的最大值的问题了,而实际上对于一个值,它会放置在(Li, Ri)的位置上。这个带插入的求二维区间最大值的问题,我们可以认为它是一个复杂度为(N * N * log * log + M * log * log)的问题,简单的来说,就是树套树问题。
但是,很容易发现的一点就是,时间卡的真的是紧,我尝试了不去sort,不离散化等方法,对于这个复杂度的做法,最后始终得到了TLE5的结果,看来得利用更小常数的做法来解决了。更小常数?二维树状数组?!
好家伙,还真是二维树状数组,经过大佬liangs333的一番教导,我明白了,如果现在有这样的一个内包含和外包含的关系[l, r]和外包含的[L, R]我们有L ≤ l ≤ r ≤ R。这个东西变种一下,因为两维均是单独成立的,所以我们对“L”这一维,进行逆处理。我们令L = N - L + 1,也就是将他们都反过来了,好家伙,这样就满足了r ≤ R,且(N - l + 1) ≤ (N - L + 1),变成了两个同时的包含关系,于是,变成了二维前缀和,于是此题虽然复杂度没有变化,但是却有了更小的常数,问题引刃而解。
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #include <bitset> #include <unordered_map> #include <unordered_set> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 #define INF 0x3f3f3f3f #define LNF 0x3f3f3f3f3f3f3f3f #define HalF (l + r)>>1 #define lsn rt<<1 #define rsn rt<<1|1 #define Lson lsn, l, mid #define Rson rsn, mid+1, r #define QL Lson, ql, qr #define QR Rson, ql, qr #define myself rt, l, r #define pii pair<int, int> #define MP(a, b) make_pair(a, b) using namespace std; typedef unsigned long long ull; typedef unsigned int uit; typedef long long ll; const int maxN = 2e3 + 5, maxM = 2e5 + 7; int N, M, tot; ll a[maxN], pre[maxN], ans[maxM]; struct node { int l, r; ll v; int id; node(int a=0, int b=0, ll c=0, int d=0):l(a), r(b), v(c), id(d) {} friend bool operator < (node e1, node e2) { return e1.v == e2.v ? e1.id < e2.id : e1.v < e2.v; } } t[maxN * maxN / 2 + maxM]; ll tree[maxN][maxN]; void update(int x, int y, ll v) { for(int i = x; i <= N; i += lowbit(i)) for(int j = y; j <= N; j += lowbit(j)) tree[i][j] = max(tree[i][j], v); } ll query(int x, int y) { ll ans = -LNF; for(int i = x; i; i -= lowbit(i)) for(int j = y; j; j -= lowbit(j)) ans = max(ans, tree[i][j]); return ans; } int main() { scanf("%d%d", &N, &M); for(int i = 1; i <= N; i ++) { scanf("%lld", &a[i]); pre[i] = pre[i - 1] + a[i]; } for(int l = 1; l <= N; l ++) for(int r = l; r <= N; r ++) t[++ tot] = node(l, r, pre[r] - pre[l - 1], 0); ll tmp; for(int i = 1, l, r; i <= M; i ++) { scanf("%d%d%lld", &l, &r, &tmp); t[++ tot] = node(l, r, tmp, i); } sort(t + 1, t + tot + 1); for(int i = 1; i <= N; i ++) for(int j = 1; j <= N; j ++) tree[i][j] = -LNF; for(int i = 1; i <= tot; i ++) { if(t[i].id) { ans[t[i].id] = query(N - t[i].l + 1, t[i].r); } else { update(N - t[i].l + 1, t[i].r, t[i].v); } } for(int i = 1; i <= M; i ++) { if(ans[i] > -LNF) printf("%lld\n", ans[i]); else printf("NONE\n"); } return 0; }