Codeforces 551E GukiZ and GukiZiana

 

[传送门]

 

分块,每一块维护一个单调递增的数组$w$,修改时因为区间加不会影响相邻元素的大小关系,所以在对于一整块的区间加打标记就行了。若不在同一块内就暴力修改每一个数,重新维护一次$w$数组,每次修改最多需要重构两块。查询操作先对每一块的$w$数组二分看存不存在$y$,最优解肯定由第一次出现$y$的块和最后一次出现$y$的块产生,然后再暴力统计这两块的$a$数组对应$y$的位置就可以了。

 

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 5e5 + 7;

int l[N], r[N], belong[N], block, num, n, q;
ll a[N], w[N], add[N];

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++) {
            w[j] = a[j];
            belong[j] = i;
        }
        sort(w + l[i], w + r[i] + 1);
    }
}

void update(int x, int y, ll val) {
    int p = belong[x], q = belong[y];
    if (p == q) {
        for (int i = x; i <= y; i++) a[i] += val;
        for (int i = l[p]; i <= r[p]; i++) w[i] = a[i];
        sort(w + l[p], w + r[p] + 1);
        return;
    }
    for (int i = p + 1; i < q; i++) add[i] += val;
    for (int i = x; i <= r[p]; i++) a[i] += val;
    for (int i = l[p]; i <= r[p]; i++) w[i] = a[i];
    sort(w + l[p], w + r[p] + 1);
    for (int i = l[q]; i <= y; i++) a[i] += val;
    for (int i = l[q]; i <= r[q]; i++) w[i] = a[i];
    sort(w + l[q], w + r[q] + 1);
}

int query(ll val) {
    int block1 = 1e6, block2 = 0;
    for (int i = 1; i <= num; i++) {
        int pos = lower_bound(w + l[i], w + r[i] + 1, val - add[i]) - w;
        if (pos >= l[i] && pos <= r[i] && w[pos] == val - add[i]) {
            block1 = min(block1, i);
            block2 = max(block2, i);
        }
    }
    if (block2 == 0) return -1;
    //cout << block1 << ' ' << block2 << '\n';
    int pos1 = 1e6, pos2 = 0;
    for (int i = l[block1]; i <= r[block1]; i++) 
        if (a[i] + add[block1] == val) {
            pos1 = min(pos1, i);
            pos2 = max(pos2, i);
        }
    for (int i = l[block2]; i <= r[block2]; i++) 
        if (a[i] + add[block2] == val) {
            pos1 = min(pos1, i);
            pos2 = max(pos2, i);
        }
    return pos2 - pos1;
}

int main() {
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++) 
        scanf("%lld", &a[i]);
    build();
    while (q--) {
        int opt;
        scanf("%d", &opt);
        if (opt == 1) {
            int l, r;
            ll x;
            scanf("%d%d%lld", &l, &r, &x);
            update(l, r, x);
        } else {
            ll val;
            scanf("%lld", &val);
            printf("%d\n", query(val));
        }
    }
    return 0;
}
View Code

 

posted @ 2019-10-14 14:23  Mrzdtz220  阅读(170)  评论(0)    收藏  举报