首页 > 其他分享 >莫队套分块-学习笔记

莫队套分块-学习笔记

时间:2025-01-20 20:44:37浏览次数:1  
标签:block2 分块 int 复杂度 sqrt 笔记 莫队

莫队套分块

P4396 [AHOI2013] 作业

题目翻译:

给定一个长度为 \(n\) 的序列,\(m\) 次询问,每一次给出 \(l,r,a,b\) 及求在区间 \([l,r]\) 间在值域 \([a,b]\) 的所有数的个数,和数的种数。

算法理解:

莫队套分块,显而易见就是在运用莫队的前提下,用分块来处理莫队的增减值。分块的复杂度为 \(m\sqrt n\) 而莫队的复杂度为 \(n \sqrt m\) 因此莫队套分块的复杂度为 \(O(n \sqrt m + m \sqrt n)\),分块的作用就是在增减值时若要枚举大量数据时可以用分块优化

思路:

\(1.\) 分析题目发现,我们可以用莫队来枚举区间,每一次枚举就将对应的值用桶储存下来,最后将要求值域的内的所有个数加上即可(求种数只用加一)。这样的复杂度为\(O(m \sqrt n + maxn\times n)\)(\(maxn\) 指值域最大值)

\(2.\) 考虑优化,既然是用分块,那我们可以将值域分成 \(\sqrt {maxn}\),再用数组储存块的左右端点,这样累加答案时只需要加上块的答案,和多余的单独答案即可,复杂度为 \(O(m\sqrt n+m\sqrt {maxn})\) (对于种数也是同理)

完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int block[N],block2[N],a[N],num[N];
int br[N],bl[N];
struct Q{
    int l,r,a,b,id;
}q[N];
bool cmp(Q x,Q y){
    if(block[x.l]!=block[y.l])return x.l<y.l;
    if(block[x.l]&1)return x.r<y.r;
    return x.r>y.r;
}
int sum[N],sum1[N];
bool vis[N];
void update(int x,int val){
    num[x]+=val;
    sum[block2[x]]+=val;
    if(num[x]==1 && val==1){
        vis[x]=1;
        sum1[block2[x]]++;
    }
    if(num[x]==0 && val==-1){
        vis[x]=0;
        sum1[block2[x]]--;
    }
}

int query(int a,int b){
    if(a>b)return 0;
    int ans=0;
    if(block2[a]==block2[b]){
        for(int i=a;i<=b;i++){
            if(vis[i])ans+=num[i];
        }
        return ans;
    }
    else{
        for(int i=a;i<=br[block2[a]];i++){
            ans+=num[i];
        }
        for(int i=bl[block2[b]];i<=b;i++){
            ans+=num[i];
        }
        for(int i=block2[a]+1;i<=block2[b]-1;i++){
            ans+=sum[i];
        }
        return ans;
    }
}
int query2(int a,int b){
    if(a>b)return 0;
    int ans=0;
    if(block2[a]==block2[b]){
        for(int i=a;i<=b;i++){
            if(vis[i])ans++;
        }
        return ans;
    }
    else{
        for(int i=a;i<=br[block2[a]];i++){
            ans+=vis[i];
        }
        for(int i=bl[block2[b]];i<=b;i++){
            ans+=vis[i];
        }
        for(int i=block2[a]+1;i<=block2[b]-1;i++){
            ans+=sum1[i];
        }
        return ans;
    }
}
void add(int x){
    update(a[x],1);
}
void del(int x){
    update(a[x],-1);
}
int ans1[N],ans2[N];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    int len=1.0*n/sqrt(m)+1;
    for(int i=1;i<=n;i++){
        block[i]=(i-1)/len+1;
    }
    int maxn=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        maxn=max(maxn,a[i]);
    }
    len=sqrt(maxn);
    for(int i=1;i<=maxn;i++){
        block2[i]=(i-1)/len+1;
    }
    int blocknum=block2[maxn];
    for(int i=1;i<=blocknum;i++){
        bl[i]=(i-1)*len+1;
        br[i]=i*len;
    }
    blocknum=block2[maxn];
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b);
        q[i].b=min(q[i].b,maxn);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    int l=1,r=0;
    for(int i=1;i<=m;i++){
        while(l<q[i].l)del(l++);
        while(l>q[i].l)add(--l);
        while(r<q[i].r)add(++r);
        while(r>q[i].r)del(r--);
        ans1[q[i].id]=query(q[i].a,q[i].b);
        ans2[q[i].id]=query2(q[i].a,q[i].b);
    }
    for(int i=1;i<=m;i++){
        printf("%d %d\n",ans1[i],ans2[i]);
    }
}

标签:block2,分块,int,复杂度,sqrt,笔记,莫队
From: https://www.cnblogs.com/XichenOC/p/18682497

相关文章

  • YOLOv10-1.1部分代码阅读笔记-model.py
    model.pyultralytics\engine\model.py目录model.py1.所需的库和模块2.classModel(nn.Module): 1.所需的库和模块#UltralyticsYOLO......
  • Doris 2.1 Queries Acceleration -Tuning Plan学习笔记
    1OptimizingTableSchemaDesign1.1Case1:TableEngineSelection1.1.1Thequeryperformanceofthesetablemodels,frombesttoworst,is:Duplicate>MOW>MOR==Aggregate.1.2Case2:BucketColumnSelection1.2.1Selectingappropriatebucket......
  • Java初学者笔记-08、IO流
    I:负责把磁盘和网络中的数据读到程序内存中去。O:负责把程序内存中的数据写到网络或者磁盘中。按照流的内容,IO流分为字节流和字符流。字节流:最小单位是字节。适合操作所有类型的文件。比如音频、视频、图片文本等的复制,转移。字符流:只适合操作纯文本文件。比如读写txt,java文件......
  • AGC005做题笔记
    AtcoderGrandContest005A-STring题目大意有一个字符串\(X\),它的字符数是偶数。其中一半字符为"S",另一半字符为"T"。现执行以下操作\(10^{10000}\)次:在\(X\)中(连续)出现的ST子串中,删除最左边的一个。如果没有出现,则不做任何操作。找出\(X\)的最终长度。解......
  • AI大模型-提示工程学习笔记9-生成知识提示
    卷首语:我所知的是我自己非常无知,所以我要不断学习。写给AI入行比较晚的小白们(比如我自己)看的,大神可以直接路过无视了。有一种改进大语言模型(LLM)推理能力的技术:生成知识作为提示的一部分。这种方法由Liu等人(2022)提出,旨在通过让模型先生成相关知识,再将这些知识整合到推理过......
  • Python Playwright学习笔记(二)
    一、模拟手机playwright.devices可以配置模拟器。importasynciofromplaywright.async_apiimportasync_playwrightasyncdefrun(playwright):iphone_12=playwright.devices['iPhone12']browser=awaitplaywright.webkit.launch(headless=False)conte......
  • uos 开发笔记
    versionGLIBCXX_3.4.26notfound的问题解决一查看是否有这个库/lib64/libstdc++.so.6二查看这个库/lib64/libstdc++.so.6中的的GLIBCXX的支持的版本 经查看是环境里已经有这个库,并且是个软连接,软连接到libstdc++.so.6.0.19 查看这个库/lib64/libstdc++.so.6中的的GLIBCX......
  • Maui学习笔记-系统主题切换
    Maui提供了一种根据当前应用程序主题设置属性的机制,但是它不包含用于在UI中切换主题的组件,需要我们自行创建。创建项目 首先创建一个ThemeInfo类来存储应用程序主题对象及标题。这些对象会在Picker元素中显示。添加CommunityToolkit.Mvvm工具包,创建一个ThemeSettings主......
  • 阅读笔记二
    团队管理与协作的艺术核心内容摘要:团队角色与职责:分析了软件开发团队中常见的角色,如项目经理、产品经理、开发人员、测试人员等,并讨论了各自的责任和协作方式。沟通与合作:强调了有效的沟通对于团队成功的关键作用,介绍了面对面会议、邮件、即时通讯等多种沟通渠道的选择与运用。......
  • JavaScript笔记APIs篇02——DOM事件
     黑马程序员视频地址:黑马程序员前端JavaScript入门到精通全套视频教程https://www.bilibili.com/video/BV1Y84y1L7Nn?vd_source=0a2d366696f87e241adc64419bf12cab&spm_id_from=333.788.videopod.episodes&p=78 目录事件监听(绑定)事件监听其他版本(了解)事件类型事件对象......