BZOJ4241 历史研究
[传送门]
感觉这种信息不符合区间可加性,或者用来区间相加的时间复杂度太高的话就直接分块。
res[i][j] 表示第 $i$ 块到第 $j$ 块之间的答案,查询就先查询整块,再对两端暴力。
注意不要用memset清空cnt数组,每次使用了再循环一遍撤销操作就行了。
#include <bits/stdc++.h> #define ll long long using namespace std; namespace IO { const int MAXSIZE = 1 << 20; char buf[MAXSIZE], *p1, *p2; #define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin), p1 == p2) ? EOF : *p1++) template<typename T> inline void read(T &x) { x = 0; T f = 1; char ch = gc(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = gc(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = gc(); } x *= f; } } using namespace IO; const int N = 1e5 + 7; const int BLOCK = sqrt(N) + 7; int n, q, a[N], v[N], tol; int l[BLOCK], r[BLOCK], block, num, belong[N]; ll res[BLOCK][BLOCK], cnt[N], sum[BLOCK][N]; template<class T> inline void checkmax(T &a, T b) { if (a < b) a = b; } void build() { block = sqrt(n); num = n / block; if (n % block) num++; for (int i = 1; i <= num; i++) l[i] = (i - 1) * block + 1, r[i] = i * block; r[num] = n; for (int i = 1; i <= num; i++) for (int j = l[i]; j <= r[i]; j++) belong[j] = i; for (int i = 1; i <= num; i++) { for (int j = 1; j <= tol; j++) cnt[j] = 0, sum[i][j] = sum[i - 1][j]; ll mx = 0; for (int j = l[i]; j <= n; j++) { cnt[a[j]] += v[a[j]]; checkmax(mx, cnt[a[j]]); res[i][belong[j]] = mx; if (j <= r[i]) sum[i][a[j]] += v[a[j]]; } } for (int i = 1; i <= tol; i++) cnt[i] = 0; } bool vis[N]; ll query(int x, int y) { int p = belong[x], q = belong[y]; if (p == q) { ll ans = 0; for (int i = x; i <= y; i++) cnt[a[i]] += v[a[i]], checkmax(ans, cnt[a[i]]); for (int i = x; i <= y; i++) cnt[a[i]] -= v[a[i]]; return ans; } ll ans = res[p + 1][q - 1]; if (p + 1 <= q - 1) { for (int i = x; i <= r[p]; i++) if (!vis[a[i]]) cnt[a[i]] += sum[q - 1][a[i]] - sum[p][a[i]], vis[a[i]] = 1; for (int i = l[q]; i <= y; i++) if (!vis[a[i]]) cnt[a[i]] += sum[q - 1][a[i]] - sum[p][a[i]], vis[a[i]] = 1; } for (int i = x; i <= r[p]; i++) { cnt[a[i]] += v[a[i]]; checkmax(ans, cnt[a[i]]); } for (int i = l[q]; i <= y; i++) { cnt[a[i]] += v[a[i]]; checkmax(ans, cnt[a[i]]); } for (int i = x; i <= r[p]; i++) { cnt[a[i]] = 0; vis[a[i]] = 0; } for (int i = l[q]; i <= y; i++) { cnt[a[i]] = 0; vis[a[i]] = 0; } return ans; } int main() { read(n), read(q); for (int i = 1; i <= n; i++) read(a[i]), v[i] = a[i]; sort(v + 1, v + 1 + n); tol = unique(v + 1, v + 1 + n) - v - 1; for (int i = 1; i <= n; i++) a[i] = lower_bound(v + 1, v + 1 + tol, a[i]) - v; build(); for (int l, r; q--; ) { read(l), read(r); printf("%lld\n", query(l, r)); } return 0; }