Codeforces #442 Div2 F

#442 Div2 F

题意

给出一些包含两种类型(a, b)问题的问题册,每本问题册有一些题目,每次查询某一区间,问有多少子区间中 a 问题的数量等于 b 问题的数量加 \(k\)

分析

令包含 a 问题的问题册的问题数取正值,包含 b 问题的问题册的问题数取负值,那么问题就是求有多少子区间的和为 \(k\)

先求前缀和,记录 \(i\) 出现的次数 \(cnt[i]\)。当计算完前缀和 \(b[i-1]\) 后,考虑前缀和 \(b[i]\)\(cnt[b[i]-k]\)为对答案的贡献。

对于这种多个区间的询问,且区间从 \([L,R]\)\([L,R+1]\)\([L-1,R]\) 只需要 \(O(1)\) 的复杂度时,可以用莫队算法去优化,离线 + 分块。

注意,并不能直接用数组去存 \(cnt\) ,用 \(map\) 也会超时,这里可以离散化掉所有可能的值,因为我们只关心某种数字出现的次数。

code

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 1e5 + 10;
const int BLOCK = 300;
int n, k;
ll a[MAXN], b[MAXN];
ll s[MAXN << 2];
int x[MAXN], y[MAXN], z[MAXN];
ll O[MAXN << 2];
struct P {
    int l, r, b, i;
    bool operator < (const P& o) const {
        if(b != o.b) return b < o.b;
        return r < o.r;
    }
}p[MAXN];
ll ans[MAXN];
int main() {
    scanf("%d%d", &n, &k);
    for(int i = 0; i < n; i++) {
        scanf("%lld", &a[i]);
        if(a[i] != 1) a[i] = -1;
    }
    for(int i = 0; i < n; i++) {
        scanf("%lld", &b[i]);
        if(!i) b[i] = a[i] * b[i];
        else b[i] = b[i - 1] + a[i] * b[i];
    }
    int c = 0;
    b[n] = 0;
    for(int i = 0; i <= n; i++) {
        s[c++] = b[i];
        s[c++] = b[i] + k;
        s[c++] = b[i] - k;
    }
    sort(s, s + c);
    int cc = unique(s, s + c) - s;
    for(int i = 0; i <= n; i++) {
        x[i] = lower_bound(s, s + cc, b[i] - k) - s;
        y[i] = lower_bound(s, s + cc, b[i]) - s;
        z[i] = lower_bound(s, s + cc, b[i] + k) - s;
    }
    int q;
    scanf("%d", &q);
    for(int i = 0; i < q; i++) {
        scanf("%d%d", &p[i].l, &p[i].r);
        p[i].l--;
        p[i].r--;
        p[i].b = p[i].l / BLOCK;
        p[i].i = i;
    }
    sort(p, p + q);
    int L = 0, R = 0;
    ll res = 0;
    for(int i = 0; i < q; i++) {
        int l = p[i].l, r = p[i].r;
        if(!i) {
            if(l == 0) O[y[n]]++;
            else O[y[l - 1]]++;
            for(int j = l; j <= r; j++) {
                res += O[x[j]];
                O[y[j]]++;
            }
        } else {
            for(int j = R + 1; j <= r; j++) {
                res += O[x[j]];
                O[y[j]]++;
            }
            for(int j = L - 1; j >= l; j--) {
                if(j == 0) { res += O[z[n]]; O[y[n]]++; }
                else { res += O[z[j - 1]]; O[y[j - 1]]++; }
            }
            for(int j = R; j > r; j--) {
                O[y[j]]--;
                res -= O[x[j]];
            }
            for(int j = L; j < l; j++) {
                if(j == 0) { O[y[n]]--; res -= O[z[n]]; }
                else { O[y[j - 1]]--; res -= O[z[j - 1]]; }
            }
        }
        L = l;
        R = r;
        ans[p[i].i] = res;
    }
    for(int i = 0; i < q; i++) printf("%lld\n", ans[i]);
    return 0;
}
posted @ 2017-11-02 00:08  ftae  阅读(125)  评论(0编辑  收藏  举报