[BZOJ4241] 历史研究

题目链接

考虑分块: 记\(Ans[i][j]\) 表示第i到第j块的答案, \(cnt[i][j]\)表示第\(j\)种颜色的块前缀和.

那么就可以直接处理了, \(Ans[i][j]\)可以通过扫描一整个块来处理, 查询的时候直接先询问大块答案, 然后小块扫描.

因为大块里面的答案它不会受到小块的影响, 而大块里面的答案小块探测不到, 所以这样做反而是可以的.


考虑分块的一般思想:块之间要支持下列操作,

  1. 快速合并信息
  2. 记住相应的信息.

这就要求信息要么是可以直接利用的答案, 要么是可以快速维护和计算的信息.

如果要有修改操作, 要么要兹词快速重构块,还可以兹词快速打标记, 想题目就可以向这一方面考虑.

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define Debug(s) debug("The massage in line %d, Function %s: %s\n", __LINE__, __FUNCTION__, s)
typedef long long LL;
typedef long double LD;
const int BUF_SIZE = (int)2e6 + 10;
struct fastIO {
    char buf[BUF_SIZE], buf1[BUF_SIZE]; int cur, cur1; FILE *in, *out;
    fastIO() { cur = BUF_SIZE, in = stdin, out = stdout; cur1 = 0; }
    inline char getchar() { if(cur == BUF_SIZE) fread(buf, BUF_SIZE, 1, in), cur = 0; return *(buf + (cur++)); }
    inline void putchar(char ch) { *(buf1 + (cur1++)) = ch; if (cur1 == BUF_SIZE) fwrite(buf1, BUF_SIZE, 1, out), cur1 = 0; }
    inline void flush() { if (cur1 > 0) fwrite(buf1, cur1, 1, out); cur1 = 0; }
}IO;
LL read() {
    char ch = IO.getchar();
    LL x = 0, flag = 1;
    for(;!isdigit(ch); ch = IO.getchar()) if(ch == '-') flag *= -1;
    for(;isdigit(ch); ch = IO.getchar()) x = x * 10 + ch - 48;
    return x * flag;
}
void write(LL x) {
    if(x < 0) x = -x, IO.putchar('-');
    if(x >= 10) write(x / 10);
    IO.putchar(x % 10 + 48);
}

const int Maxn = 1e5 + 9, Maxb = 209;
int n, q, a[Maxn], Temp[Maxn], len;

namespace Bl {
    int Block[Maxn], Begin[Maxn], End[Maxn], cnt[Maxb][Maxn], Lim, tot, tmp[Maxn];
    LL ans[Maxb][Maxb];
    
    void init() {
        Lim = 700, tot = (n - 1) / Lim + 1;
        rep (i, 1, n) {
            Block[i] = (i - 1) / Lim + 1;
            ++cnt[Block[i]][a[i]];
        }
        rep (i, 1, tot) Begin[i] = End[i - 1] + 1, End[i] = End[i - 1] + Lim;
        End[tot] = min(End[tot], n);

        rep (i, 1, tot)
            rep (j, 1, len) cnt[i][j] += cnt[i - 1][j];

        rep (i, 1, tot) 
            rep (j, i, tot) {
                ans[i][j] = ans[i][j - 1];
                rep (k, Begin[j], End[j]) 
                    ans[i][j] = max(ans[i][j], 1ll * (cnt[j][a[k]] - cnt[i - 1][a[k]]) * Temp[a[k]]);
            }
    }

    LL query(int l, int r) {
        if(Block[l] == Block[r]) {
            LL res = 0;
            rep (i, l, r) ++tmp[a[i]];
            rep (i, l, r) res = max(res, 1ll * tmp[a[i]] * Temp[a[i]]);
            rep (i, l, r) --tmp[a[i]];
            return res;
        }
        
        LL res = ans[Block[End[Block[l]] + 1]][Block[Begin[Block[r]] - 1]];
        rep (i, l, End[Block[l]]) ++tmp[a[i]];
        rep (i, Begin[Block[r]], r) ++tmp[a[i]];

        rep (i, l, End[Block[l]]) res = max(res, 1ll * Temp[a[i]] * (cnt[Block[Begin[Block[r]] - 1]][a[i]] - cnt[Block[End[Block[l]] + 1] - 1][a[i]] + tmp[a[i]]));
        rep (i, Begin[Block[r]], r) res = max(res, 1ll * Temp[a[i]] * (cnt[Block[Begin[Block[r]] - 1]][a[i]] - cnt[Block[End[Block[l]] + 1] - 1][a[i]] + tmp[a[i]]));

        rep (i, l, End[Block[l]]) --tmp[a[i]];
        rep (i, Begin[Block[r]], r) --tmp[a[i]];
        return res;
    }
}

void discrete() {
    rep (i, 1, n) Temp[i] = a[i];
    sort(Temp + 1, Temp + n + 1);
    len = unique(Temp + 1, Temp + n + 1) - Temp - 1;
    rep (i, 1, n) a[i] = lower_bound(Temp + 1, Temp + len + 1, a[i]) - Temp;
}

void init() {
    n = read(); q = read();
    rep (i, 1, n) a[i] = read();
    discrete();
    Bl :: init();
}

void solve() {
    while(q--) {
        LL l = read(), r = read();
        printf("%lld\n", Bl :: query(l, r));
    }
}

int main() {
    freopen("photo.in", "r", stdin);
    freopen("photo.out", "w", stdout);

    init();
    solve();
#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;
}

posted @ 2019-01-26 20:51 Qrsikno 阅读(...) 评论(...) 编辑 收藏