当前位置: 首页 > 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.lryc.cn/news/621116.html

相关文章:

  • 浏览器面试题及详细答案 88道(34-44)
  • 宝塔配置反向代理
  • 机器学习基础讲解
  • Linux:Samba 服务部署
  • 机器学习学习总结
  • 基于机器学习的文本情感极性分析系统设计与实现
  • 【深度学习】深度学习的四个核心步骤:从房价预测看机器学习本质
  • 机器学习--KNN算法
  • 减重小知识
  • AI幻觉终结之后:GPT-5开启的“可靠性”新赛道与开发者生存指南
  • 系统思考:转型困扰与突破
  • [ HTML 前端 ] 语法介绍和HBuilderX安装
  • 语义 HTML 的核心价值:提升 SEO 与 AI 理解
  • 解剖HashMap的put <五> JDK1.8
  • scikit-learn/sklearn学习|广义线性回归 Logistic regression的三种成本函数
  • Android POS应用在android运行常见问题及解决方案
  • 【数据结构初阶】--排序(一):直接插入排序,希尔排序
  • 前端框架选择之争:jQuery与Vue在现代Web开发中的真实地位-优雅草卓伊凡
  • 机器学习核心概念与实践笔记
  • spring mvc HttpMessageConverter 消息转换器
  • 【互动屏幕】解析双屏联动在数字展厅中的应用与价值
  • 系统升级后客户端缓存问题的无感知解决方案
  • [激光原理与应用-273]:理论 - 波动光学 - 光是电磁波,本身并没有颜色,可见光的颜色不过是人的主观感受
  • 网络组播技术详解
  • 考研408《计算机组成原理》复习笔记,第五章(3)——CPU的【数据通路】
  • 深入理解管道(上):PowerShell 管道参数绑定原理与高频范式
  • 玩转QEMU硬件模拟器 - Versatilepb模拟器开发概述
  • MySql——聚簇索引(主键索引)和非聚簇索索引(非主键索引)引区别(即聚集索引和非聚集索引区别)
  • IPv6互联网地址解析
  • [论文阅读] 人工智能 + 软件工程 | 代码变更转自然语言生成中的幻觉问题研究解析