【[Ynoi2018]五彩斑斓的世界】

分块毒瘤题。如果真的想好好练习思维以及代码的话就请不要使用\(\text{WC}\)讲过的黑科技指令集。

正文部分:

由乃题必定分块。
我们可以将同一个块内值相同的用并查集维护起来,因为如果是一个块内相同的值打标机怎么改都一样。
接着谈修改,我们设块内最大值为\(\text{mx}\),修改的值为\(\text{v}\)
如果\(v*2>mx\)的话就改大于\(\text{v}\)的,否则就改小于\(\text{v}\)
原理是因为如果大于\(\text{v}\)的比较少的话改大的,否则改小的。
改小的时候我们可以把小的数全部加上\(\text{v}\),然后对这个块打上一个减标记。

My Code:

// luogu-judger-enable-o2
#pragma GCC optimize("Ofast,fast-math")
#pragma GCC target("avx,avx2")
#include <bits/stdc++.h>
#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define _max(x,y) (x > y ? x : y)
using namespace std;
static char buf[100000],*p1,*p2;
static char pbuf[1000000],*pp(pbuf),st[15];
inline int read() {
    register int res(0);register char c(gc);
    while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') res = res * 10 + c - 48,c = gc;
    return res;
}
inline void print(register int v) {
    if(!v) *pp++ = 48;
    else { 
        register int tp(0);
        while(v) st[++tp] = v % 10 + 48,v /= 10;
        while(tp) *pp++ = st[tp--];
    }
    *pp++ = '\n';
}
int fa[100010],a[100010],bel[100010];
int bl[320],br[320],Max[320],tag[320];
int root[320][100010];    
unsigned short cnt[100010];
int n,m,i,j,k,bls;
int getf(int o) {
    if(o == fa[o]) return o;
    else return fa[o] = getf(fa[o]);
}
inline void build(int num) {
    Max[num] = 0;
    for(register int i = bl[num];i <= br[num];++i) {
        if(!root[num][a[i]]) {
            root[num][a[i]] = i;
            fa[i] = i;
            cnt[root[num][a[i]]] = 1;
        } else {
            fa[i] = root[num][a[i]];
            cnt[root[num][a[i]]]++;
        }
        Max[num] = _max(Max[num],a[i]);
    }
    return;
}
inline void pd(int num) {
    for(register int i = bl[num];i <= br[num];++i) {
        a[i] = a[getf(i)];
        cnt[root[num][a[i]]] = 0;root[num][a[i]] = 0;
    }
    for(register int i = bl[num];i <= br[num];++i) {
        a[i] -= tag[num];fa[i] = 0;
    }
    tag[num] = 0;
    return;
}
inline void change1(int l,int r,int x) {
    for(register int i = bel[l];i <= bel[r];++i) pd(i); 
    for(register int i = l;i <= r;++i) {
        if(a[i] > x) a[i] -= x;
    }
    for(register int i = bel[l];i <= bel[r];++i) build(i);
    return;
}
inline void rpl(int x,int y,int z) {
    if(!root[x][y]) return;
    if(!root[x][z]) {
        root[x][z] = root[x][y];
        cnt[root[x][z]] = cnt[root[x][y]];
        a[root[x][y]] = z;          
    } else {
        fa[root[x][y]] = root[x][z];
        cnt[root[x][z]] += cnt[root[x][y]];
    }
    root[x][y] = 0;
    cnt[root[x][y]] = 0;
    return;
}
inline void change2(int num,int val) {
    if(val >= Max[num] - tag[num]) return;
    if(val << 1 > Max[num] - tag[num]) {
        for(register int i = tag[num] + val + 1;i <= Max[num];++i) rpl(num,i,i - val);
     //   Max[num] -= val;Chkmax(Max[num],val + tag[num]);
        Max[num] = _max(Max[num] - val,val + tag[num]);
    } else {
        for(register int i = tag[num] + 1;i <= tag[num] + val;++i) rpl(num,i,i + val);
        tag[num] += val;
    }
    return;
}
inline void modify(int l,int r,int x) {
    if(bel[l] + 1 >= bel[r]) {
        change1(l,r,x);
        return;
    }
    change1(l,br[bel[l]],x);change1(bl[bel[r]],r,x);
    for(int i = bel[l] + 1;i < bel[r];++i) change2(i,x);
    return;
}
inline int ask1(int l,int r,int x) {
    int res = 0;
    for(int i = l;i <= r;++i) {
        if(a[getf(i)] - tag[bel[i]] == x) res++;
    }
    return res;
}
inline int ask2(int num,int val) {
    if(val + tag[num] >= 100000) return 0;
    return cnt[root[num][val + tag[num]]];
}
inline int query(int l,int r,int x) {
    if(bel[l] + 1 >= bel[r]) return ask1(l,r,x);
    int res = ask1(l,br[bel[l]],x) + ask1(bl[bel[r]],r,x);         
    for(int i = bel[l] + 1;i < bel[r];i++) res += ask2(i,x);
    return res;
}
int main() {
    n = read();m = read();bls = sqrt(n) + 1;
    for(register int i = 1;i <= n;++i) {
        a[i] = read();
        bel[i] = (i - 1) / bls + 1;
        if(!bl[bel[i]]) bl[bel[i]] = i;
        br[bel[i]] = i;
    }
    for(register int i = 1;i <= bel[n];++i) build(i);
    while(m--) {
        int opt,l,r,x;opt = read();l = read();r = read();x = read();
        if(opt == 1) modify(l,r,x);
        else {
            print(query(l,r,x)); 
        }
    }
    fwrite(pbuf,1,pp-pbuf,stdout);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Sai0511/p/10360348.html