• 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, Mleq 10) 并且 (B) 是一个 (1 o 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
    ", 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;
    }
    
  • 相关阅读:
    初始线程(相关理论)
    python并发编程之多进程2-(数据共享及进程池和回调函数)
    python并发编程之多进程1--(互斥锁与进程间的通信)
    Cpython支持的进程与线程
    网络编程之进程理论简介
    python之网络socket编程
    Gray码 (格雷码) 【二进制】
    [BZOJ 2350] [Poi2011] Party 【Special】
    [BZOJ 1033] [ZJOI2008] 杀蚂蚁antbuster 【模拟!】
    [BZOJ 3209] 花神的数论题 【数位统计】
  • 原文地址:https://www.cnblogs.com/VeniVidiVici/p/11762711.html
Copyright © 2020-2023  润新知