当前位置: 首页 > news >正文

莫队 + 离散化 Ann and Books

题目链接:Problem - F - Codeforces

题目大意:

n (n <= 1e5) 本书,一类是数学书一类是经济书,每本书上都有若干道题目 (ai <= 1e9)。

q (q <= 1e5) 次查询,每次查询一段区间 [l,r] ,求 [l,r] 内所有满足 " 数学书的题目数量之和 - 经济书的题目数量之和 = k " (每个询问的 k 都是同一个固定值)的所有子区间的数量

Solution:

无修改,区间查询,k 值固定,可以离线,又想到莫队了。

首先肯定预处理经济书的数目为负值,这样我们就可以简化问题为:一段连续区间的和 = k

于是可以前缀和快速计算,下面记作 pre 数组。

考虑移动区间时如何计算答案的变化,先考虑 add 操作,sub 操作就是逆过程

1. 当前区间 [l,r] ,添加 r+1 (下面记作 x)这个位置的值,计算对答案增加的贡献:

    增加的贡献就是 "后缀和 = k" 的子区间的数目。

    即:pre[x] - pre[i-1] == k  ->  pre[i-1] == pre[x] - k  ( i-1 \in  [l-1,r] )

2. 当前区间 [l,r] ,添加 l-1 (下面记作 x)这个位置的值,计算对答案增加的贡献:   

    增加的贡献就是 "缀和 = k" 的子区间的数目。

    即:pre[i] - pre[x-1] == k  ->  pre[i] == pre[x-1] + k  ( i \in  [l-1,r] )

于是问题就转化为了:维护区间内 pre[i] 等于 "pre[x] - k" 和 "pre[x-1] + k" 的 i 的个数,我们可以维护 [l,r] 范围内的,至于 l-1 这样边界的地方特判就好了。sub 就是逆过程。

还有个问题是,用 map 直接维护会多带一个 log ,而开一个 int 类型的桶又会超空间。

注意到无修改且 k 固定的情况下,每个位置 i 要维护的就只是 pre[i] + k 和 pre[i] - k,因此所有要维护的值不会很多,因此用离散化预处理后就可以开个 int 类型的桶维护了。

还有个细节是我们在 第二种情况 里,有一项是 "pre[x-1] + k" ,当x = 1的时候 x-1 = 0,也就是说我们还需要维护 0 这个位置的贡献,要把 -k,0,k 这三个数都放进去一起离散化

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;#define N 100005int n,m,p,B,bel[N];
long long k,w[N],b[N],c[N * 3],pre[N],ans[N],res,cnt[N * 3];struct Node
{int id0,id1,id2;
}a[N * 3];struct Query
{int l,r,id;
}q[N];int get(long long x) { return lower_bound(c + 1,c + m + 1,x) - c ;}int cmp(Query x,Query y)
{if(bel[x.l] == bel[y.l]) return x.r < y.r ;return x.l < y.l ;
}void add(int x,int op)
{if(!op) res += cnt[a[x - 1].id2];else res += cnt[a[x].id0];++ cnt[a[x].id1];return;
}void sub(int x,int op)
{-- cnt[a[x].id1];if(!op) res -= cnt[a[x - 1].id2];else res -= cnt[a[x].id0];return;
}int main()
{memset(cnt,0,sizeof cnt);scanf("%d%lld",&n,&k),pre[0] = res = 0ll,m = 0;for (int i = 1;i <= n;++ i) scanf("%lld",&b[i]);for (int i = 1;i <= n;++ i){scanf("%lld",&w[i]);if(b[i] == 2) w[i] = -1ll * w[i];pre[i] = pre[i - 1] + w[i];c[++ m] = pre[i] - k;c[++ m] = pre[i];c[++ m] = pre[i] + k;}c[++ m] = -k;c[++ m] = 0ll;c[++ m] = k;sort(c + 1,c + m + 1);m = unique(c + 1,c + m + 1) - c - 1;for (int i = 0;i <= n;++ i)a[i].id0 = get(pre[i] - k),a[i].id1 = get(pre[i]),a[i].id2 = get(pre[i] + k);scanf("%d",&p);B = (int)sqrt(n);for (int i = 1;i <= p;++ i){scanf("%d%d",&q[i].l,&q[i].r);q[i].id = i;bel[i] = (i - 1) / B + 1;}sort(q + 1,q + p + 1,cmp);int l,r;l = 1,r = 0;for (int i = 1;i <= n;++ i){while (l > q[i].l) add(-- l,0),res += (w[l] == k);while (l < q[i].l) res -= (w[l] == k),sub(l ++,0);while (r < q[i].r) add(++ r,1),res += (pre[l - 1] == pre[r] - k);while (r > q[i].r) res -= (pre[l - 1] == pre[r] - k),sub(r --,1);ans[q[i].id] = res;}for (int i = 1;i <= p;++ i) printf("%lld\n",ans[i]);return 0;
}

http://www.dtcms.com/a/332050.html

相关文章:

  • 【19-模型训练细节 】
  • 业务敏捷性对SAP驱动型企业意味着什么?如何保持企业敏捷性?
  • 零信任架构(Zero Trust Architecture, ZTA)(通过动态验证和最小权限控制,实现对所有访问请求的严格授权和持续监控)
  • latex 中破折号的输入
  • 介绍java中atomic及相关类
  • PERC初探暨小试牛刀
  • Vue3 vxeTree树形组件完全指南:从入门到精通的完整使用教程
  • QT6(可视化UI设计代码实现)
  • MATLAB实现图像增强(直方图均衡化)
  • 数学分析| 极限论| 1.数列极限常用方法总结
  • App冷启动阶段Open Dexfiles实现原理【ART虚拟机系列2】
  • docker nginx 定时脚本保存30天日志信息
  • MFC的使用——使用ChartCtrl绘制曲线
  • 2025.8.13~14 实习总结
  • 计算机网络技术学习-day1《网络乾坤:从比特洪流到协议星河的奇幻之旅》​
  • MCU中的LTDC(LCD-TFT Display Controller)
  • 网卡聚合teamdctl
  • 大模型技术栈全景
  • Java 图片像素碰撞检测
  • Linux软件编程-进程(1)
  • 【嵌入式C语言】四
  • 【PCB设计经验】3D模型在线预览!效率便捷!
  • pycharm远程连接服务器跑实验详细操作
  • ClickHouse 日常运维命令总结
  • 并发编程原理与实战(二十三)StampedLock应用实战与其他锁性能对比分析
  • CentOS7系统负载异常飙高全链路分析详细指南
  • Kaggle赛题分析1:Elo用户忠诚度评分预测(2)-特征工程与模型训练
  • 解决Python环境混乱问题
  • 【159页PPT】智慧方案企业数字化转型流程体系建设与运营方案(附下载方式)
  • 鸿蒙应用开发实战:模块内页面路由与Navigation导航详解