luogu P4117 [Ynoi2018] 五彩斑斓的世界

https://www.luogu.com.cn/problem/P4117

因为题目的值域只有 1 0 5 10^5 105,并且只有减法一种操作,所以我们可以考虑均摊
把所有的减法改成加法
首先还是要分块,维护它的最大值 m x mx mx,如果当前修改 x x x

  • 2 x > = m x 2x>=mx 2x>=mx,就把所有 > x >x >x的全部减去 x x x
  • 否则就把所有 < = x <=x <=x的加上 x x x再把整个块 − x -x x

那么这个时间复杂度是多少呢?
考虑第一种情况,相当于是用 O ( m x − x ) O(mx-x) O(mxx)的时间把 m x mx mx变成了最大为 x x x的一个数,那么最少减少了 m x − x mx-x mxx
对于第二种情况,相当于是用 O ( x ) O(x) O(x)的时间把最大值mx减少了 x x x
那么时间复杂度只和值域有关,即是 O ( n ) O(n) O(n)同阶的

具体写起来就是对于每个块,把每个询问和修改都丢上去,如果完全包含,就整块处理,不然就暴力重构,用并查集维护每个权值即可

有亿点卡常
code:

#include<bits/stdc++.h>
#define N 1000050
#define RE register
using namespace std;

int fa[N], rt[N], size[N], val[N], a[N], n, m, blo, bel[N], mx, tg, ans[N >> 1];
inline int get(int x) { return fa[x] == x? x : fa[x] = get(fa[x]); }
inline void merge(int x, int y) {
    if(!rt[y]) {
        rt[y] = rt[x];
        val[rt[y]] = y;
    } else fa[rt[x]] = rt[y];
    size[y] += size[x]; rt[x] = size[x] = 0;
}
inline void build(int l, int r) {
    memset(rt, 0, sizeof rt);
    memset(size, 0, sizeof size);
    mx = tg = 0;
    for(RE int i = l; i <= r; i ++) { mx = max(mx, a[i]);
        if(rt[a[i]]) fa[i] = rt[a[i]];
        else {
            fa[i] = rt[a[i]] = i;
            val[i] = a[i];
        }
        size[a[i]] ++;
    }
}
inline void change(int l, int r, int x) {
    if(x * 2 <= mx - tg) {
        for(RE int j = tg + 1; j <= tg + x; j ++)
            if(rt[j]) merge(j, j + x);
        tg += x;
    } else {
        for(RE int j = mx; j > x + tg; j --)
            if(rt[j]) merge(j, j - x);
        if(x < mx - tg) mx = tg + x;
    }
}
inline void calc(int l, int r, int L, int R, int x, int id) {
    if(x + tg > 100001) return ;
//     if(id == 2) {
//            printf("  %d %d    %d\n", l, r, x + tg);
//            for(int i = 1; i <= n; i ++) printf("%d ", val[get(i)]); printf("\n");
//        }
    if(L <= l && r <= R) ans[id] += size[x + tg];
    else {
        for(RE int i = max(l, L); i <= min(r, R); i ++)
            if(val[get(i)] == x + tg) ans[id] ++;
    }
}
inline void rebuild(int l, int r, int L, int R, int x) {
    for(RE int i = l; i <= r; i ++) a[i] = val[get(i)], size[a[i]] = rt[a[i]] = 0, a[i] -= tg;
    for(RE int i = l; i <= r; i ++) val[i] = 0;
    for(RE int i = max(l, L); i <= min(r, R); i ++)
        if(a[i] > x) a[i] -= x;
    
    mx = tg = 0;
    for(RE int i = l; i <= r; i ++) { mx = max(mx, a[i]);
        if(rt[a[i]]) fa[i] = rt[a[i]];
        else {
            fa[i] = rt[a[i]] = i;
            val[i] = a[i];
        }
        size[a[i]] ++;
    }
}
struct Q {
    int o, l, r, x, id;
} q[N >> 1];
inline int read() {
    register int x = 0;
    register char ch = getchar();
    for(; ch < '0' || ch > '9'; ) ch = getchar();
    for(; ch >= '0' && ch <= '9'; ) x = (x << 3) + (x << 1) + (ch - 48), ch = getchar();
    return x;
}
inline void write(register int x) {
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
int main() {
    n = read(), m = read();
    for(RE int i = 1; i <= n; i ++) a[i] = read();
    blo = 1200;
  // blo = min(n, 2 * m / (int)sqrt(n) + 1);
    for(RE int i = 1; i <= n; i ++) bel[i] = (i - 1) / blo + 1;
  //  printf("** %d\n", blo);
    int tot = 0;
    for(RE int i = 1; i <= m; i ++) q[i].o = read(), q[i].l = read(), q[i].r = read(), q[i].x = read(), q[i].id = q[i].o == 2? ++ tot : 0;
    
    for(RE int i = 1; i <= bel[n]; i ++) {
        int l = (i - 1) * blo + 1, r = min(n, i * blo);
        build(l, r);
        for(RE int j = 1; j <= m; j ++) {
            int L = q[j].l, R = q[j].r, x = q[j].x, o = q[j].o, id = q[j].id;
            if(R < l || L > r) continue;
            if(o == 1) {
                if(L <= l && r <= R) change(l, r, x);
                else rebuild(l, r, L, R, x);
             //   printf("   %d %d %d %d %d        %d\n", l, r, L, R, x, ans[2]);
            } else calc(l, r, L, R, x, id);
        }
    }
    for(RE int i = 1; i <= tot; i ++) write(ans[i]), puts("");
    return 0;
}
/*
10 5
3 4 6 6 4 4 9 9 7 6
2 5 9 3
1 1 3 3
1 6 10 2
1 10 10 8
2 4 10 6
  */
posted @ 2021-08-26 14:59  lahlah  阅读(35)  评论(0编辑  收藏  举报