Welcome home, Chtholly & [Ynoi2018]五彩斑斓的世界

前几天写莫队有点上瘾,想起好久没有写过分块了,就来写一道分块题

题意很简单

给定一个序列,要求维护以下操作
把区间\([l,r]\)中所有大于\(x\)的数减去\(x\)
查询区间\([l,r]\)中等于\(x\)的数的个数

很显然的,这些操作都主要与权值有关
所以按权值维护
但是任意区间不方便维护,考虑分块

同一个块中如果只有整块的修改
显然如果两个位置权值一样
不管怎么改还是一样的
所以可以用并查集
只修改一个点,合并也是\(O(1)\)

但是如果直接修改所有大于\(x\)的显然会超时
所以如果大于\(x\)的比较少就直接修改大于\(x\)的(复杂度\(O(max-x)\)\(max\)是块内最大值)
否则修改小于等于\(x\)的部分(加上\(x\)),然后打一个整块减的标记(复杂度\(O(x)\))
具体来说如果\(x*2>max\)就改大的部分否则改小的部分
因为每次修改都会使\(max\)减小\(x\)且每次复杂度都是\(O(x)\)
所以均摊复杂度\(O(n*\sqrt n)\)

然后写出来,调试了半天,终于过了

然后打开五彩斑斓的世界直接把Welcome home, Chtholly的代码交上去

MLE,\(30pts\)
发现空间限制变成了原来的\(\frac{1}{4}\)
卡空间后在BZOJ交了一发,过了
兴高采烈地又去洛谷交了一发,TLE\(90pts\)
发现时间限制变成了原来的\(\frac{1}{3}\)

于是又卡了半个小时的常
最后改得无比丑陋终于卡过了

\(100pts\)代码惨不忍睹
还是贴\(90pts\)的吧

#include<bits/stdc++.h>

using namespace std;

#define gc c=getchar()
#define r(x) read(x)

template<typename T>
inline void read(T&x){
    x=0;T k=1;char gc;
    while(!isdigit(c)){if(c=='-')k=-1;gc;}
    while(isdigit(c)){x=x*10+c-'0';gc;}x*=k;
}

const int N=1e5+7;
const int len=320;


int fa[N];
inline int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}

int mx[len],L[len],R[len];
int rt[len][N];
unsigned short cnt[N];
int a[N];
inline void build(int x){
    mx[x]=0;
    for(int i=L[x];i<=R[x];++i){
        if(!rt[x][a[i]]){
            rt[x][a[i]]=i;
            fa[i]=i;
            cnt[rt[x][a[i]]]=1;
            mx[x]=max(mx[x],a[i]);
        }
        else {
            fa[i]=rt[x][a[i]];
            cnt[rt[x][a[i]]]++;
        }
    }
}

int tag[len];
inline void pushdown(int x){
    for(int i=L[x];i<=R[x];++i){
        a[i]=a[find(i)];
        cnt[rt[x][a[i]]]=0;
        rt[x][a[i]]=0;
    }
    for(int i=L[x];i<=R[x];++i)a[i]-=tag[x];
    for(int i=L[x];i<=R[x];++i)fa[i]=0;
    tag[x]=0;
}

unsigned short be[N];
inline void modify1(int l,int r,int v){
    for(int i=be[l];i<=be[r];++i)pushdown(i);
    for(int i=l;i<=r;++i)if(a[i]>v)a[i]-=v;
    for(int i=be[l];i<=be[r];++i)build(i);
}

inline void insert(int x,int p,int q){
    if(!rt[x][p])return;
    if(!rt[x][q]){
        rt[x][q]=rt[x][p];
        cnt[rt[x][q]]=cnt[rt[x][p]];
        a[rt[x][p]]=q;
    }
    else {
        fa[rt[x][p]]=rt[x][q];
        cnt[rt[x][q]]+=cnt[rt[x][p]];
    }
    rt[x][p]=0;
    cnt[rt[x][p]]=0;
}

inline void modify2(int x,int v){
    if(v>=mx[x]-tag[x])return;
    if(v*2>mx[x]-tag[x]){
        for(int i=v+tag[x]+1;i<=mx[x];++i)insert(x,i,i-v);
        mx[x]=max(mx[x]-v,v+tag[x]);
    }
    else {
        for(int i=tag[x]+1;i<=tag[x]+v;++i)insert(x,i,i+v);
        tag[x]+=v;
    }
}

inline void modify(int l,int r,int v){
    if(be[l]+1>=be[r])modify1(l,r,v);
    else {
        modify1(l,R[be[l]],v);
        modify1(L[be[r]],r,v);
        for(int i=be[l]+1;i<be[r];++i)modify2(i,v);
    }
}

inline int query1(int l,int r,int v){
    int ret=0;
    for(int i=l;i<=r;++i)if(a[find(i)]-tag[be[i]]==v)ret++;
    return ret;
}

inline int query2(int x,int v){
    if(v+tag[x]>1e5)return 0;
    return cnt[rt[x][v+tag[x]]];
}

inline int query(int l,int r,int v){
    if(be[l]+1>=be[r])return query1(l,r,v);
    else {
        int ret=query1(l,R[be[l]],v)+query1(L[be[r]],r,v);
        for(int i=be[l]+1;i<be[r];++i)ret+=query2(i,v);
        return ret;
    }
}

int main(){
    int n,m;r(n),r(m);
    int block_size=sqrt(n);
    for(int i=1;i<=n;++i){
        r(a[i]);
        be[i]=(i-1)/block_size+1;
        if(!L[be[i]])L[be[i]]=i;
        R[be[i]]=i;
    }
    for(int i=1;i<=be[n];++i)build(i);
    for(int opt,l,r,x;m;--m){
        r(opt),r(l),r(r),r(x);
        if(opt==1)modify(l,r,x);
        else printf("%d\n",query(l,r,x));
    }
}

猜你喜欢

转载自www.cnblogs.com/yicongli/p/9831742.html
今日推荐