(分块)洛谷 P2801 教主的魔法 题解

news2025/3/21 0:39:06

之前学过 莫队 算法,其运用了分块思想;但是我居然是第一次写纯种的分块题目。

题意

给你一个长度为 n n n 的序列 a a a(一开始 ∀ a i ∈ [ 1 , 1000 ] \forall a_i\in[1,1000] ai[1,1000])。要求执行 q q q 次操作,操作有两种,每次形如 o p , l , r , w / c op,l,r,w/c op,l,r,w/c

  • o p op op M \rm M M,将 a l , a l + 1 , ⋯   , a r a_l,a_{l+1},\cdots,a_r al,al+1,,ar 分别加上 w w w
  • o p op op A \rm A A,查询 a l , a l + 1 , ⋯   , a r a_l,a_{l+1},\cdots,a_r al,al+1,,ar 中,有多少个数大于 c c c

n ≤ 1 0 6 , q ≤ 3000 , w ≤ 1000 , c ≤ 1 0 9 n\le10^6,q\le3000,w\le1000,c\le10^9 n106,q3000,w1000,c109

思路

主席树?是我早就不会打的。

如果我们把它变成一道分块练习题呢?

考虑对序列 a a a 分块,对于每一块内,使用辅助数组 b b b 以保证块内数有序。不妨设 b l t , b r t bl_t,br_t blt,brt 表示块 t t t 的左右端点, b e l i bel_i beli 表示下标 i i i 所在的块的编号。

对于修改操作 l , r , w l,r,w l,r,w,如果 ∃ t , b l t ≤ l < r ≤ b r t \exist t,bl_t\le l<r\le br_t t,bltl<rbrt,即同一块, t = b e l l = b e l r t=bel_l=bel_r t=bell=belr,如果其不在左右端点上,那么块内的排序性质就会被破坏;反之如果它们不在同一块,说明它们中间跨过了若干块整块的区间,我们发现被跨过的区间仍然保持有序

那么我们得到一个初步的修改方法:

  • 设左右端点所在的块分别在 l b = b e l l , r b = b e l r lb=bel_l,rb=bel_r lb=bell,rb=belr,如果 l b = r b lb=rb lb=rb,就块内暴力加 w w w 并快排更新;
  • 否则即 l b < r b lb<rb lb<rb,我们发现块 l b + 1 ∼ r b − 1 lb+1\sim rb-1 lb+1rb1 内仍然有序,那么不妨想线段树引入懒惰标记一样,我们搞一个加法标记,把整一块 t t t 内所有元素同时加的数,用 t a g t tag_t tagt 记录下来,等到查询时再处理;只强制更新更新 l ∼ b r l b l\sim br_{lb} lbrlb b l r b ∼ r bl_{rb}\sim r blrbr 的数据和块 l b , r b lb,rb lb,rb

这样子大大减少了排序的次数,每次修改操作顶多 2 × log ⁡ 2 n 2\times \log_2n 2×log2n,瓶颈在于快排。

void modify(ll t)//更新t块内数据
{
    for(int i=bl[t];i<=br[t];i++)
    b[i]=a[i];
    sort(b+bl[t],b+br[t]+1);
}
void add(ll ql,ll qr,ll x)//l,r,w
{
    ll lb=bel[ql],rb=bel[qr];//左右端所在块
    if(lb==rb)//同一块
    {
        for(int i=ql;i<=qr;i++)
        a[i]+=x;
        modify(lb);
        return;
    }
    //不同块
    for(int i=ql;i<=br[lb];i++)
    a[i]+=x;
    for(int i=bl[rb];i<=qr;i++)
    a[i]+=x;
    modify(lb);
    modify(rb);
    for(int i=lb+1;i<rb;i++)//lb+1~rb-1块打标记
    tag[i]+=x;
}

接下来就是查询,其实就和修改所运用的思想差不多了。同样讨论 l , r l,r l,r 在或不在同一块的两种情况。如果同一块就直接 q l ∼ q r ql\sim qr qlqr 扫过去(倒着枚举提前 break 凹时间也行、甚至乎二分,反正块上数组 b b b 就是有序的),不同块就搜左右两边 l ∼ b r r b l\sim br_{rb} lbrrb b l r b ∼ r bl_{rb}\sim r blrbr(这里不能二分,因为原数组并非有序),至于中间的整块整块的,按块二分就好。

ll find(ll ql,ll qr,ll x)
{
	ll l=ql,r=qr;
	while(l<=r)
	{
		ll mid=(l+r)>>1;
		if(b[mid]<x)l=mid+1;
		else r=mid-1;
	}
	return qr-l+1;
}
ll query(ll ql,ll qr,ll x)
{
    ll ret=0,lb=bel[ql],rb=bel[qr];
    if(lb==rb)
    {
        ret+=find(ql,qr,x-tag[lb]);
        return ret;
    }
	for(int i=ql;i<=br[lb];i++)
	if(a[i]+tag[lb]>=x)ret++;
	for(int i=bl[rb];i<=qr;i++)
	if(a[i]+tag[rb]>=x)ret++;
    for(int i=lb+1;i<rb;i++)
    ret+=find(bl[i],br[i],x-tag[i]);
    return ret;
}

块长 n \sqrt{n} n ,修改一次是块长+块内排序,查询是 块内二分 或 块长扫左右端+块数*块内二分,时间复杂度 Θ ( m n + m n log ⁡ 2 n ) = Θ ( m n log ⁡ 2 n ) \Theta(m\sqrt{n}+m\sqrt{n}\log_2\sqrt{n})=\Theta(m\sqrt{n}\log_2\sqrt{n}) Θ(mn +mn log2n )=Θ(mn log2n )

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e6+9;
ll n,q,a[N];
ll tag[N];//加法标记
ll bSize,cnt_b,bel[N],bl[N],br[N],b[N];
void init()
{
    bSize=sqrt(n);
    cnt_b=n/bSize;
    if(n%bSize)cnt_b++;
    for(int i=1;i<=n;i++)
    {
        bel[i]=(i-1)/bSize+1;
        b[i]=a[i];
    }
    for(int i=1;i<=cnt_b;i++)
    {
        bl[i]=(i-1)*bSize+1;
        br[i]=i*bSize;
    }
    br[cnt_b]=n;
    for(int i=1;i<=cnt_b;i++)
    sort(b+bl[i],b+br[i]+1);
}
void modify(ll t)//更新t块内数据
{
    for(int i=bl[t];i<=br[t];i++)
    b[i]=a[i];
    sort(b+bl[t],b+br[t]+1);
}
void add(ll ql,ll qr,ll x)
{
    ll lb=bel[ql],rb=bel[qr];//左右端所在块
    if(lb==rb)//同一块
    {
        for(int i=ql;i<=qr;i++)
        a[i]+=x;
        modify(lb);
        return;
    }
    //不同块
    for(int i=ql;i<=br[lb];i++)
    a[i]+=x;
    for(int i=bl[rb];i<=qr;i++)
    a[i]+=x;
    modify(lb);
    modify(rb);
    for(int i=lb+1;i<rb;i++)//lb+1~rb-1块打标记
    tag[i]+=x;
}
ll find(ll ql,ll qr,ll x)
{
	ll l=ql,r=qr;
	while(l<=r)
	{
		ll mid=(l+r)>>1;
		if(b[mid]<x)l=mid+1;
		else r=mid-1;
	}
	return qr-l+1;
}
ll query(ll ql,ll qr,ll x)
{
    ll ret=0,lb=bel[ql],rb=bel[qr];
    if(lb==rb)
    {
        ret+=find(ql,qr,x-tag[lb]);
        return ret;
    }
	for(int i=ql;i<=br[lb];i++)
	if(a[i]+tag[lb]>=x)ret++;
	for(int i=bl[rb];i<=qr;i++)
	if(a[i]+tag[rb]>=x)ret++;
    for(int i=lb+1;i<rb;i++)
    ret+=find(bl[i],br[i],x-tag[i]);
    return ret;
}
int main()
{
    scanf("%lld%lld",&n,&q);
    for(int i=1;i<=n;i++)
    scanf("%lld",&a[i]);
    init();
    while(q--)
    {
        char op;
        ll l,r,x;
        cin>>op;
        scanf("%lld%lld%lld",&l,&r,&x);
        if(op=='M')add(l,r,x);
        else printf("%lld\n",query(l,r,x));
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2318669.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[蓝桥杯 2023 省 B] 飞机降落(不会dfs的看过来)

[蓝桥杯 2023 省 B] 飞机降落 题目描述 N N N 架飞机准备降落到某个只有一条跑道的机场。其中第 i i i 架飞机在 T i T_{i} Ti​ 时刻到达机场上空&#xff0c;到达时它的剩余油料还可以继续盘旋 D i D_{i} Di​ 个单位时间&#xff0c;即它最早可以于 T i T_{i} Ti​ 时刻…

信创系统极速文件查找:locate 命令详解

原文链接&#xff1a;信创系统极速文件查找&#xff1a;locate 命令详解 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇信创终端操作系统上 locate 命令详解的文章。在 Linux 及信创终端操作系统&#xff08;如 统信 UOS、麒麟 KOS&#xff09;中&#xff0c;查找…

C# | 超简单CSV表格读写操作(轻松将数据保存到CSV,并支持读取还原)

C# | 超简单CSV表格读写操作&#xff08;轻松将数据保存到CSV&#xff0c;并支持读取还原&#xff09; 文章目录 C# | 超简单CSV表格读写操作&#xff08;轻松将数据保存到CSV&#xff0c;并支持读取还原&#xff09;一、上位机开发中的CSV应用背景二、CSV读写实战教学1. 基本对…

PostgreSQL:语言基础与数据库操作

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

蓝桥杯学习——二叉树+奇点杯题目解析

基础认知 一、二叉树种类&#xff1a; 1.满二叉树。记深度k&#xff0c;节点数量2^k-1。 2.完全二叉树&#xff1a;除了底层&#xff0c;其余全满&#xff0c;底部从左到右连续。 3&#xff0c;平衡二叉搜索树&#xff1a;左子树和右子树高度差不大于1。 二、存储方式&…

基于django+vue的购物商城系统

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.8数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页 热卖商品 优惠资讯 个人中心 后台登录 管理员功能界面 用户管理 商品分类管理…

AI安全、大模型安全研究(DeepSeek)

DeepSeek 点燃AI应用革命之火,但安全 “灰犀牛” 正在逼近 DeepSeek-R1国产大模型的发布,以技术创新惊艳了全球,更是极致的性价比推动国内千行百业接入 AI,政府、企业竞速开发智能业务处理、智能客服、代码生成、营销文案等应用,“落地效率” 成为第一关键词。然而与此相…

卷积神经网络 - 汇聚层

卷积神经网络一般由卷积层、汇聚层和全连接层构成&#xff0c;本文我们来学习汇聚层。 汇聚层(Pooling Layer)也叫子采样层(Subsampling Layer)&#xff0c;其作用是进 行特征选择&#xff0c;降低特征数量&#xff0c;从而减少参数数量。 卷积层虽然可以显著减少网络中连接的…

论文分享:PL-ALF框架实现无人机低纹理环境自主飞行

在室内仓库、地下隧道等低纹理复杂场景中&#xff0c;无人机依赖视觉传感器进行自主飞行时&#xff0c;往往会遇到定位精度低、路径规划不稳定等难题。针对这一问题&#xff0c;重庆邮电大学计算机学院雷大江教授团队在IEEE Trans期刊上提出了一种新型自主飞行框架&#xff1a;…

Nodejs使用redis

框架&#xff1a;koa&#xff0c;通过koa-generator创建 redis: 本地搭建&#xff0c;使用默认帐号&#xff0c;安装说明地址以及默认启动设置&#xff1a;https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/ 中间件&#x…

GitHub 超火的开源终端工具——Warp

Warp 作为近年来 GitHub 上备受瞩目的开源终端工具&#xff0c;以其智能化、高性能和协作能力重新定义了命令行操作体验。以下从多个维度深入解析其核心特性、技术架构、用户评价及生态影响力&#xff1a; 一、背景与核心团队 Warp 由前 GitHub CTO Jason Warner 和 Google 前…

计算机视觉技术探索:美颜SDK如何利用深度学习优化美颜、滤镜功能?

时下&#xff0c;计算机视觉深度学习正在重塑美颜技术&#xff0c;通过智能人脸检测、AI滤镜、深度美肤、实时优化等方式&#xff0c;让美颜效果更加自然、精准、个性化。 那么&#xff0c;美颜SDK如何结合深度学习来优化美颜和滤镜功能&#xff1f;本文将深入解析AI在美颜技术…

应用商店上新:Couchbase Enterprise Server集群

可移植的冗余数据平台&#xff0c;这往往是创建可扩展的云原生应用程序的先决条件。而不依赖特定平台的工具可用于为多云、多区域工作负载提供企业级应用所需的灵活性。 ​Couchbase是一种高性能NoSQL数据库&#xff0c;专为当今复杂的云生态系统所需的动态扩展能力而设计。最近…

Redis解决缓存击穿问题——两种方法

目录 引言 解决办法 互斥锁&#xff08;强一致&#xff0c;性能差&#xff09; 逻辑过期&#xff08;高可用&#xff0c;性能优&#xff09; 设计逻辑过期时间 引言 缓存击穿&#xff1a;给某一个key设置了过期时间&#xff0c;当key过期的时候&#xff0c;恰好这个时间点对…

集成学习之随机森林

目录 一、集成学习的含义 二、集成学习的代表 三、集成学习的应用 1、分类问题集成。&#xff08;基学习器是分类模型&#xff09; 2、回归问题集成。&#xff08;基学习器是回归模型&#xff09; 3、特征选取集成。 四、Bagging之随机森林 1、随机森林是有多个决策树&a…

在线JSON格式校验工具站

在线JSON校验格式化工具&#xff08;Be JSON&#xff09;在线,JSON,JSON 校验,格式化,xml转json 工具,在线工具,json视图,可视化,程序,服务器,域名注册,正则表达式,测试,在线json格式化工具,json 格式化,json格式化工具,json字符串格式化,json 在线查看器,json在线,json 在线验…

SAP的WPS导出找不到路径怎么办;上载报错怎么办

一.打开注册编辑器 二.输入以下地址 计算机\HKEY_CLASSES_ROOT\ExcelWorksheet\Protocol\StdFileEditing\Server 去除掉EXE后面的命令即可 二&#xff1a;WPS上载文件没反应怎么办 如何切换整合模式或多组件模式-WPS学堂 根据官方操作把整合模式改成多组件模式

Moonlight-16B-A3B: 变革性的高效大语言模型,凭借Muon优化器打破训练效率极限

近日&#xff0c;由Moonshot AI团队推出的Moonlight-16B-A3B模型&#xff0c;再次在AI领域引发了广泛关注。这款全新的Mixture-of-Experts (MoE)架构的大型语言模型&#xff0c;凭借其创新的训练优化技术&#xff0c;特别是Muon优化器的使用&#xff0c;成功突破了训练效率的极…

rust学习笔记17-异常处理

今天聊聊rust中异常错误处理 1. 基础类型&#xff1a;Result 和 Option&#xff0c;之前判断空指针就用到过 Option<T> 用途&#xff1a;表示值可能存在&#xff08;Some(T)&#xff09;或不存在&#xff08;None&#xff09;&#xff0c;适用于无需错误信息的场景。 f…

PyTorch系列教程:使用预训练语言模型增强文本分类

文本分类仍是自然语言处理&#xff08;NLP&#xff09;领域的一项基础任务&#xff0c;其目标是将文本数据归入预先设定的类别之中。预训练语言模型的出现极大地提升了这一领域的性能。本文将探讨如何利用 PyTorch 来利用这些模型&#xff0c;展示它们如何能增强文本分类任务。…