• 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
    ",query(l,r,x));
        }
    }
    
  • 相关阅读:
    android -------- Data Binding的使用(二)
    牛客网-《剑指offer》-数值的整数次方[快速幂运算]
    牛客网-《剑指offer》-二进制中1的个数
    牛客网-《剑指offer》-矩形覆盖
    牛客网-《剑指offer》-变态跳台阶
    牛客网-《剑指offer》-跳台阶
    牛客网-《剑指offer》-斐波那契数列
    牛客网-《剑指offer》-旋转数组的最小数
    牛客网-《剑指offer》-用两个栈实现队列
    牛客网-《剑指offer》-重建二叉树
  • 原文地址:https://www.cnblogs.com/yicongli/p/9831742.html
Copyright © 2020-2023  润新知