51nod 1463 找朋友

题意

给定两个长度为 \(N\) 的数列 \(A,B\),一个大小为 \(M\) 的集合 \(K\)

\(Q\) 次询问,每次询问 \([l,r]\),输出区间内满足 \(|B_i-B_j|\in K\) 的最大 \(A_i+A_j\)

满足 \(N,Q \leq 10^5, M\leq 10\) 并且 \(B\) 是一个 \(1 \to N\) 的排列


解法

虽然很巧,但是好像这类题的套路都很相似。。

发现 \(M\) 很小,考虑暴力枚举 \(K\) 中的元素 \(K_i\)

那么询问 \([l,r]\) 对于我们枚举的 \(K_i\) 就转化为了输出满足 \(|B_i-B_j|=K\) 的最大 \(A_i+A_j\)

我们把询问离线下来按照右端点排序

每次新加入一个 \(B_i\),就在它之前寻找满足 \(|B_i-B_j|=K\)\(j\) 位置,并把 \(A_i+A_j\) 这一贡献加入 \(j\) 位置(取最大值转移)

可以发现对于一个 \(B_i\),满足条件的 \(B_j\) 最多只有两个,又 \(B\) 是一个排列,所以完全可以映射值与位置找到 \(j\) 位置

那么对于一个右端点为 \(R\) 的询问,我们用线段树维护一下 \([L,R]\) 中的最大值即可,之前的处理方式可以保证线段树中 \([L,R]\) 存储的值一定是在 \([L,R]\) 之间的 \(A_i+A_j\) 点对


代码

#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>

using namespace std;

#define rep(i, a, b) for (int i = a; i <= b; ++i)
#define per(i, a, b) for (int i = a; i >= b; --i)

const int MAX_N = 5e5 + 10;

int read();

struct qry { int l, id; };

int N, Q, M;

int a[MAX_N], b[MAX_N], k[20];
int pos[MAX_N], ans[MAX_N];

vector<qry> q[MAX_N];

inline void chkmax(int& x, int v) { x = x > v ? x : v; }

struct SegTree {
#define ls(x) x << 1
#define rs(x) x << 1 | 1

    int val[MAX_N << 2];

    void clear() { memset(val, 0, sizeof val); }

    void pushup(int x) { val[x] = max(val[ls(x)], val[rs(x)]); }

    void modify(int x, int l, int r, int k, int v) {
        if (l == r)  return chkmax(val[x], v), void();
        int mid = (l + r) >> 1;
        if (k <= mid)
            modify(ls(x), l, mid, k, v);
        else
            modify(rs(x), mid + 1, r, k, v);
        pushup(x);
    }

    int query(int x, int l, int r, int ql, int qr) {
        if (ql <= l && r <= qr)  return val[x];
        int mid = (l + r) >> 1, res = 0;
        if (ql <= mid)
            chkmax(res, query(ls(x), l, mid, ql, qr));
        if (qr > mid)
            chkmax(res, query(rs(x), mid + 1, r, ql, qr));
        return res;
    }

#undef ls
#undef rs
} tr;

int main() {

    N = read(), Q = read(), M = read();

    rep (i, 1, N)  a[i] = read();
    rep (i, 1, N)  b[i] = read(), pos[b[i]] = i;
    rep (i, 1, M)  k[i] = read();

    rep (i, 1, Q) {
        int l = read(), r = read();
        q[r].push_back((qry){l, i});
    }

    rep (i, 1, M) {
        int K = k[i];
        tr.clear();
        rep (j, 1, N) {
            if (b[j] > K && pos[b[j] - K] <= j)
                tr.modify(1, 1, N, pos[b[j] - K], a[j] + a[pos[b[j] - K]]);
            if (b[j] + K <= N && pos[b[j] + K] <= j)
                tr.modify(1, 1, N, pos[b[j] + K], a[j] + a[pos[b[j] + K]]);
            for (int p = 0, s = q[j].size(); p < s; ++p) 
                chkmax(ans[q[j][p].id], tr.query(1, 1, N, q[j][p].l, j));
        }
    }

    rep (i, 1, Q)  printf("%d\n", ans[i]);

    return 0;
}

int read() {
    int x = 0, c = getchar();
    while (!isdigit(c))  c = getchar();
    while (isdigit(c))   x = x * 10 + c - 48, c = getchar();
    return x;
}

猜你喜欢

转载自www.cnblogs.com/VeniVidiVici/p/11762711.html
今日推荐