分块与莫队

分块与莫队

莫队只学了不同,带修和回滚。 我太菜

分块九讲:

推博:「分块」数列分块入门1 – 9 by hzwer

代码直接看 loj

  1. 数列分块入门 2

    对于块内排序即可。

  2. 数列分块入门 3

    也是排序。

    不同的是可以用 set 维护,比较方便。

  3. 数列分块入门 4

    同线段树,写 tag 就行了。

  4. 数列分块入门 5

    考虑开很少次根号就会都变 1,维护区间和,区间是否都为一,暴力对不为一的修改。

  5. 数列分块入门 6

    其实本题不随机。

    直接分块插入。

    在不随机数据下可以重构分块。

  6. 数列分块入门 7

    同线段树,注意 tag 转移顺序。

    考虑 (a+b)c=ac+bc 所以乘的时候也乘一下加法 tag,最后先乘在加。

  7. 数列分块入门 8

    类似区间根号,判断区间是否全相等即可。

    也可以珂朵莉

  8. 数列分块入门 9(蒲公英)

    分块:

    类似HH的项链等题。

    整块预处理出 a 块到 b 块众数和数出现次数。

    众数直接预处理,数出现次数可以用数的位置二分,也可以前缀和。(虽然二分多 log 但是实测二分更快)

    散块直接暴力求和,因为只有散块出现的数才有可能更新众数。

    注意块大小不是 n

    莫队:

    离线

    回滚板子,加数比减数好维护。

其他:

  1. Bounce 弹飞绵羊

    在同一块内路径压缩。

    就可以将单次修改和查询整成根号

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
    #define For_(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
    const int N=2e5+4,S=1e3+3;
    int n,m;
    namespace IO{
    template<typename T> inline void write(T x){
    static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
    do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
    }
    template<typename T> inline void read(T &x){
    char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
    while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x;
    }
    }
    namespace IO{
    template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
    inline void write(const char c){putchar(c);}
    inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
    template<typename T> inline void Write(T x){write(x);putchar(' ');}
    inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
    inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
    template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
    template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class DB{
    private:
    int val[N],to[N],cst[N],pos[N],bg[S],ed[S],len;
    public:
    inline void Update(int id){
    For_(j,ed[id],bg[id],1){
    to[j]=val[j]+j;cst[j]=1;
    if(to[j]<=ed[id]) cst[j]+=cst[to[j]],to[j]=to[to[j]];
    // cout<<j<<' '<<to[j]<<' '<<cst[j]<<endl;
    }
    }
    inline void Init(int n){
    len=sqrt(n);
    For(i,1,n,1){
    int p=pos[i]=(i-1)/len+1;
    if(!bg[p]) bg[p]=i; ed[p]=i;
    read(val[i]),to[i]=val[i];
    }
    For(i,1,pos[n],1) Update(i);
    }
    inline void Add(int x,int t){val[x]=t,Update(pos[x]);}
    inline int Get(int x){
    int cnt=0;
    while(x<=n) cnt+=cst[x],x=to[x];
    return cnt;
    }
    }db;
    int main(){
    #ifndef ONLINE_JUDGE
    freopen("in_out/in.in","r",stdin);
    freopen("in_out/out.out","w",stdout);
    #endif
    read(n),db.Init(n);
    read(m);
    For(i,1,m,1){
    int opt,x,t;read(opt,x); x++;
    if(opt==1) write(db.Get(x),'\n');
    else read(t),db.Add(x,t);
    }
    }
  2. 数颜色

    分块:

    修改不多于 1000,所以类似分块 9 暴力修改即可。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
    #define For_(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
    const int N=5e4+4,S=1e3+2,M=1e6+4;
    int n,m;
    namespace IO{
    template<typename T> inline void write(T x){
    static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
    do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
    }
    template<typename T> inline void read(T &x){
    char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
    while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x;
    }
    }
    namespace IO{
    template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
    inline void write(const char c){putchar(c);}
    inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
    template<typename T> inline void Write(T x){write(x);putchar(' ');}
    inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
    inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
    template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
    template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class DB{
    private:
    int a[N],to[M],pos[N],bg[S],ed[S],qs[S][N],tt[S][S],len,tot;
    bool cnt[N];
    queue<int> que;
    public:
    inline void init(int n){
    len=sqrt(n);
    For(i,1,n,1){
    int p=pos[i]=(i-1)/len+1,x; read(x);
    if(!bg[p]) bg[p]=i; ed[p]=i;
    if(to[x]) a[i]=to[x];
    else a[i]=to[x]=++tot;
    }// init
    For(i,1,pos[n],1){
    For(j,1,n,1) qs[i][j]=qs[i-1][j];
    For(j,bg[i],ed[i],1) qs[i][a[j]]++;
    For(j,i,pos[n],1){
    tt[i][j]=tt[i][j-1];
    For(k,bg[j],ed[j],1)
    if(!cnt[a[k]]) tt[i][j]++,cnt[a[k]]=1;
    }
    memset(cnt,0,sizeof cnt);
    }// qs & tt
    }
    #define check(l,r,t) (qs[r][t]-qs[l][t])
    inline int Get(int l,int r){
    int L=pos[l],R=pos[r],ans=0;
    if(L==R)
    For(i,l,r,1) {if(!cnt[a[i]]) ans++,cnt[a[i]]=1,que.push(a[i]);}
    else{
    ans=tt[L+1][R-1];
    For(i,l,ed[L],1) if(!cnt[a[i]]&&!check(R-1,L,a[i])) ans++,cnt[a[i]]=1,que.push(a[i]);
    For(i,bg[R],r,1) if(!cnt[a[i]]&&!check(R-1,L,a[i])) ans++,cnt[a[i]]=1,que.push(a[i]);
    }
    while(!que.empty()) cnt[que.front()]=0,que.pop();
    return ans;
    }
    inline void Upd(int x,int t){
    if(!to[t]) to[t]=++tot; t=to[t];
    int P=pos[x],nw=a[x]; a[x]=t;
    For(i,P,pos[n],1) qs[i][nw]--;
    For(i,1,P,1) For(j,P,pos[n],1) if(!check(i-1,j,nw)) tt[i][j]--;
    For(i,P,pos[n],1) qs[i][t]++;
    For(i,1,P,1) For(j,P,pos[n],1) if(check(i-1,j,t)==1) tt[i][j]++;
    }
    #undef check
    }db;
    int main(){
    #ifndef ONLINE_JUDGE
    freopen("in_out/in.in","r",stdin);
    freopen("in_out/out.out","w",stdout);
    #endif
    read(n,m);db.init(n);
    For(i,1,m,1){
    char opt;scanf(" %c",&opt);
    int l,r;read(l,r);
    if(opt=='Q') write(db.Get(l,r),'\n');
    else db.Upd(l,r);
    }
    }

    莫队:

    带修板子,多一维时间。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
    #define For_(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
    const int N=5e4+3,R=1e6+4;
    namespace IO{
    int READ_NONPARAMETRIC_INIT;
    template<typename T> inline void write(T x){
    static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
    do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
    }
    template<typename T> inline T read(T &x=READ_NONPARAMETRIC_INIT){
    char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
    while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x; return x;
    }
    }
    namespace IO{
    template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
    inline void write(const char c){putchar(c);}
    inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
    template<typename T> inline void Write(T x){write(x);putchar(' ');}
    inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
    inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
    template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
    template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    namespace MD{
    int pos[N],ed[N],val[N],ans[N],cnt[R],n,m,Len,qtot,rtot,cas;
    struct Q{
    int l,r,t,id;
    inline void Rd(int a,int b){read(l,r),t=a,id=b;}
    bool operator<(Q b){return (pos[l]^pos[b.l])?pos[l]<pos[b.l]:((pos[r]^pos[b.r])?pos[r]<pos[b.r]:t<b.t);}
    }cq[N];
    struct R{
    int p,val;
    inline void Rd(){read(p,val);}
    }cr[N];
    inline void Ins(int x){cas+=!cnt[x]++;}
    inline void Del(int x){cas-=!--cnt[x];}
    inline void Mdf(int t,int l,int r){
    int p=cr[t].p;
    if(l<=p&&p<=r) Del(val[p]),Ins(cr[t].val);
    swap(val[p],cr[t].val);
    }
    inline void Init(){
    read(n,m);Len=pow(n,2.0/3.0);
    For(i,1,n,1) pos[i]=(i-1)/Len+1,ed[pos[i]]=i,read(val[i]);
    For(i,1,m,1){
    char x;scanf(" %c",&x);
    if(x=='Q') cq[++qtot].Rd(rtot,qtot);
    else cr[++rtot].Rd();
    }
    sort(cq+1,cq+qtot+1);
    }
    inline void Solve(){
    int l=1,r=0,t=0;
    For(i,1,qtot,1){
    int ql=cq[i].l,qr=cq[i].r,qt=cq[i].t,id=cq[i].id;
    while(l<ql) Del(val[l++]);
    while(l>ql) Ins(val[--l]);
    while(r<qr) Ins(val[++r]);
    while(r>qr) Del(val[r--]);
    while(t<qt) Mdf(++t,ql,qr);
    while(t>qt) Mdf(t--,ql,qr);
    ans[id]=cas;
    }
    For(i,1,qtot,1) write(ans[i],'\n');
    }
    }
    int main(){
    #ifndef ONLINE_JUDGE
    freopen("in_out/in.in","r",stdin);
    freopen("in_out/out.out","w",stdout);
    #endif
    MD::Init(),MD::Solve();
    }
  3. 颜色

    分别维护 a 块到 b 块数量前缀和和平方前缀和。

    散块算贡献即可。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
    #define For_(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
    #define ing long long
    const int N=5e4,S=40,M=2e4;
    int n,m,q;
    llt ans;
    namespace IO{
    template<typename T> inline void write(T x){
    static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
    do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
    }
    template<typename T> inline void read(T &x){
    char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
    while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x;
    }
    }
    namespace IO{
    template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
    inline void write(const char c){putchar(c);}
    inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
    template<typename T> inline void Write(T x){write(x);putchar(' ');}
    inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
    inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
    template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
    template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class DB{
    private:
    int val[N],pos[N],bg[S],ed[S],Len;
    llt qf[S][S][M],s[S][M],cnt[M];
    public:
    inline llt Sum(int L,int R,int k){if(L>R) return 0;return s[R][k]-s[L-1][k];}
    inline llt Pow(llt a){return a*a;}
    inline void Init(int n,int m){
    Len=pow(n,2.0/3);
    For(i,1,n,1){
    int p=pos[i]=(i-1)/Len+1;
    if(!bg[p]) bg[p]=i; ed[p]=i;
    read(val[i]);
    }
    For(i,1,pos[n],1){
    For(j,1,m,1) s[i][j]=s[i-1][j];
    For(j,bg[i],ed[i],1) s[i][val[j]]++;
    }
    For(i,1,pos[n],1) For(j,i,pos[n],1){
    For(k,1,m,1) qf[i][j][k]=Pow(Sum(i,j,k));
    For(k,1,m,1) qf[i][j][k]+=qf[i][j][k-1];
    }
    }
    inline llt Get(int l,int r,int a,int b){
    int L=pos[l],R=pos[r];
    llt ans=0;
    if(L==R){
    For(i,l,r,1) if(a<=val[i]&&val[i]<=b) cnt[val[i]]++;
    For(i,l,r,1) if(cnt[val[i]]) ans+=Pow(cnt[val[i]]),cnt[val[i]]=0;
    }else{
    ans+=(qf[L+1][R-1][b]-qf[L+1][R-1][a-1]);
    For(i,l,ed[L],1) if(a<=val[i]&&val[i]<=b) cnt[val[i]]++;
    For(i,bg[R],r,1) if(a<=val[i]&&val[i]<=b) cnt[val[i]]++;
    For(i,l,ed[L],1)
    if(cnt[val[i]]) ans+=(Pow(cnt[val[i]]+Sum(L+1,R-1,val[i]))-Pow(Sum(L+1,R-1,val[i]))),cnt[val[i]]=0;
    For(i,bg[R],r,1)
    if(cnt[val[i]]) ans+=(Pow(cnt[val[i]]+Sum(L+1,R-1,val[i]))-Pow(Sum(L+1,R-1,val[i]))),cnt[val[i]]=0;
    }
    return ans;
    }
    }db;
    signed main(){
    #ifndef ONLINE_JUDGE
    freopen("in_out/in.in","r",stdin);
    freopen("in_out/out.out","w",stdout);
    #endif
    read(n,m,q); db.Init(n,m);
    For(i,1,q,1){
    int l,r,a,b;read(l,r,a,b);
    l^=ans,r^=ans,a^=ans,b^=ans;
    write(ans=db.Get(l,r,a,b),'\n');
    }
    }
  4. 作业

    莫队套值域分块。

    第一问显然,第二问值域分块维护一下莫队的移动。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
    #define For_(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
    const int N=1e6+4,M=1e6+4;
    int n,m;
    namespace IO{
    int READ_NONPARAMETRIC_INIT;
    template<typename T> inline void write(T x){
    static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
    do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
    }
    template<typename T> inline T read(T &x=READ_NONPARAMETRIC_INIT){
    char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
    while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x; return x;
    }
    }
    namespace IO{
    template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
    inline void write(const char c){putchar(c);}
    inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
    template<typename T> inline void Write(T x){write(x);putchar(' ');}
    inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
    inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
    template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
    template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class DB{
    private:
    static const int S=1e3+3;
    int val[N],pos[N],sum[S],bg[S],ed[S],Len=1000;
    public:
    DB(){For(i,1,N-2,1){int p=pos[i]=(i-1)/Len+1; if(!bg[p]) bg[p]=i; ed[p]=i;}}
    inline void Add(int x,int t){val[x]+=t,sum[pos[x]]+=t;}
    inline bool Empty(int x){return val[x]==0;}
    inline int Sum(int l,int r){
    int L=pos[l],R=pos[r],ans=0;
    if(L==R) For(i,l,r,1) ans+=val[i];
    else{
    For(i,l,ed[L],1) ans+=val[i];
    For(i,bg[R],r,1) ans+=val[i];
    For(i,L+1,R-1,1) ans+=sum[i];
    }
    return ans;
    }
    }kd,sm;
    namespace MD{
    int pos[N],val[N],Len;
    pair<int,int> ans[M];
    struct Q{
    int l,r,a,b,id;
    inline void Rd(int x){read(l,r,a,b),id=x;}
    bool operator<(Q x){return (pos[l]^pos[x.l])?pos[l]<pos[x.l]:((pos[l]&1)?r>x.r:r<x.r);}
    }qst[N];
    inline void Init(int n,int m){
    Len=sqrt(n);
    For(i,1,n,1) pos[i]=(i-1)/Len+1,read(val[i]);
    For(i,1,m,1) qst[i].Rd(i);
    sort(qst+1,qst+m+1);
    }
    inline void ins(int x){sm.Add(val[x],1);if(kd.Empty(val[x])) kd.Add(val[x],1);}
    inline void del(int x){sm.Add(val[x],-1);if(sm.Empty(val[x])) kd.Add(val[x],-1);}
    inline void Solve(){
    int l=1,r=0;
    For(i,1,m,1){
    int ql=qst[i].l,qr=qst[i].r,a=qst[i].a,b=qst[i].b,id=qst[i].id;
    while(l>ql) ins(--l);
    while(r<qr) ins(++r);
    while(l<ql) del(l++);
    while(r>qr) del(r--);
    ans[id]={sm.Sum(a,b),kd.Sum(a,b)};
    }
    For(i,1,m,1) Write(ans[i].first,ans[i].second,'\n');
    }
    }
    int main(){
    #ifndef ONLINE_JUDGE
    freopen("in_out/in.in","r",stdin);
    freopen("in_out/out.out","w",stdout);
    #endif
    read(n,m),MD::Init(n,m);
    MD::Solve();
    }
posted @   5k_sync_closer  阅读(19)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示