wmz的数数(数状数组)

题目描述

\(wmz\)从小就显现出了过人的天赋,他出生的第三天就证明了哥德巴赫猜想,第五天就证明了质能方程,出生一星期之后,他觉得\(P\)是否等于\(NP\)这个问题比前面他证明的这些定理好玩多了,于是他成为了一名计算机科学家。

在他开始接触计算机科学的第一天,他就已经刷遍了所有\(oj\),这为他今后建立王国推行全民刷题计划打下了坚实的基础。在他接触计算机科学一星期之后,他就已经通读了所有顶级会议的\(paper\),并且在多方面同时出了许多成果。

他对他王国的国民智商有非常高的要求,他为想加入他的王国国籍的人准备了很多试题去测试智商,但因为他接触计算机科学第一天学到的东西就已经超过正常人一生的水平了,所以他出的试题水平在他接触计算机科学\(1\)分钟以内的水平。

-------------------------------------------吹牛分割线------------------------------------------------

\(wmz\)拥有一个长度为\(n\)的数字序列,他向你询问了\(q\)个问题,每个问题都是告诉你两个数\(L\)和\(R\),问你在序列的第\(L\)到第\(R\)个数的这一段序列中,有多少个数字\(k\),满足在这一段中恰好出现了\(k\)次。

输入格式

输入的第一行为两个整数\(n\),\(q\),表示序列的长度和问题的个数。

接下来一行有\(n\)个整数,表示\(wmz\)的数字序列。

接下来\(q\)行,每行有两个整数\(L\),\(R\),其含义如题目中所示。

输出格式

输出共\(q\)行,每行有一个整数,表示第\(i\)个问题的答案。

样例

样例输入

7 2

3 1 2 2 3 3 7

1 7

3 4

样例输出

3

1

数据范围与提示

对于\(30\%\)的数据,保证\(1 \leq n,q \leq 100\);

对于\(70\%\)的数据,保证\(1 \leq n,q \leq 10^5\);

对于\(100\%\)的数据,保证\(1 \leq n,q \leq 10^6\),序列中的每个数都在\([1,n]\)范围内

分析

用莫队离线处理可以拿到\(70\)分

然而对于\(10^6\)的数据显然会超时

\(100\)分的做法要维护一个数组\(t[i]\),代表如果选择\(i\)这个位置上的数,答案将会增加\(t[i]\)

对于一个区间来说,如果在区间中有某一个数\(i\),它在位置\(x\)上恰好是第\(i\)次出现,那么我们需要将\(t[x]\)加一

如果它在位置\(y\)上恰好是第\(i+1\)次出现,那么我们需要将\(t[y]\)减一

每次询问的答案就是询问区间中\(t\)数组的和

因为对于左端点不同的区间,某一个数\(i\)第几次出现的位置是不同的

因此我们将左端点从大到小排序,用一个代表左端点的指针向左扫

每次扫到一个值时,我们要先把上一次对这个值的操作撤销,然后看它是否满足加一或者减一的条件,对其进行新的操作

区间求和用数状数组维护即可

代码

#include<cstdio>
#include<vector>
#include<algorithm>
const int maxn=1e6+5;
std::vector<int>g[maxn];
inline int read(){
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
int n,q,a[maxn],ans[maxn],tr[maxn],sygz[maxn],sygy[maxn];
struct jl{
int l,r,id;
}b[maxn];
bool cmp(jl aa,jl bb){
return aa.l>bb.l;
}
int ef(int val,int wz){
int l=1,r=g[val].size(),mids;
while(l<=r){
mids=(l+r)>>1;
if(g[val][mids-1]>wz) r=mids-1;
else if(g[val][mids-1]<wz) l=mids+1;
else return mids;
}
return 0;
}//二分查找当前数是第几次出现
int lb(int xx){
return xx&-xx;
}
void ad(int wz,int val){
for(int i=wz;i<maxn;i+=lb(i)){
tr[i]+=val;
}
}
int qh(int wz){
int anss=0;
for(int i=wz;i>0;i-=lb(i)){
anss+=tr[i];
}
return anss;
}
int main(){
n=read(),q=read();
for(int i=1;i<=n;i++){
a[i]=read();
g[a[i]].push_back(i);
}
for(int i=1;i<=q;i++){
b[i].l=read(),b[i].r=read();
b[i].id=i;
}
std::sort(b+1,b+1+q,cmp);
int latl=n+1;//维护指针
for(int i=1;i<=q;i++){
while(latl>b[i].l){
latl--;
int wz=ef(a[latl],latl);
int tail=wz+a[latl]-1;
if(sygz[a[latl]]!=0) ad(sygz[a[latl]],-1);
if(sygy[a[latl]]!=0) ad(sygy[a[latl]],1);
//撤销上一次操作
if(tail>g[a[latl]].size()) continue;
else if(tail==g[a[latl]].size()){
ad(g[a[latl]][tail-1],1);
sygz[a[latl]]=g[a[latl]][tail-1];
sygy[a[latl]]=0;
}
else {
ad(g[a[latl]][tail-1],1);
ad(g[a[latl]][tail],-1);
sygz[a[latl]]=g[a[latl]][tail-1];
sygy[a[latl]]=g[a[latl]][tail];
}
}
ans[b[i].id]=qh(b[i].r)-qh(b[i].l-1);
}
for(int i=1;i<=q;i++){
printf("%d\n",ans[i]);
}
return 0;
}

wmz的数数(数状数组)的更多相关文章

  1. hdoj 1166 敌兵布阵 线段数和树状数组

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  2. SCAU-1144 数星星-HDU-1166-树状数组的应用

    本文借鉴代码提供:https://www.cnblogs.com/geek1116/p/5566709.html树状数组详解:https://www.cnblogs.com/xenny/p/97396 ...

  3. BZOJ 2120 数颜色(树状数组套主席树)

    1A啊,激动. 首先,不修改的情况下可以直接用主席树搞,修改的话,直接用主席树搞一次修改的情况下复杂度是O(nlogn)的. 就像你要求区间和一样,用前缀和查询是O(1),修改是O(n),只不过主席树 ...

  4. 树状数组求逆序对:POJ 2299、3067

    前几天开始看树状数组了,然后开始找题来刷. 首先是 POJ 2299 Ultra-QuickSort: http://poj.org/problem?id=2299 这题是指给你一个无序序列,只能交换 ...

  5. FZU 2029 买票问题 树状数组+STL

    题目链接:买票问题 思路:优先队列维护忍耐度最低的人在队首,leave操作ok. vis数组记录从1到n的编号的人们是不是在队列中,top维护队首的人的编号.pop操作搞定. 然后,check操作就是 ...

  6. HDU 5775 树状数组

    Bubble Sort Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  7. Ping pong(树状数组经典)

    Ping pong Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  8. poj2299树状数组入门,求逆序对

    今天入门了树状数组 习题链接 https://blog.csdn.net/liuqiyao_01/article/details/26963913 离散化数据:用一个数组来记录每个值在数列中的排名,不 ...

  9. 【bzoj2384】[Ceoi2011]Match 特殊匹配条件的KMP+树状数组

    题目描述 给出两个长度分别为n.m的序列A.B,求出B的所有长度为n的连续子序列(子串),满足:序列中第i小的数在序列的Ai位置. 输入 第一行包含两个整数n, m (2≤n≤m≤1000000).  ...

  10. Codeforces Round #401 (Div. 1) C(set+树状数组)

    题意: 给出一个序列,给出一个k,要求给出一个划分方案,使得连续区间内不同的数不超过k个,问划分的最少区间个数,输出时将k=1~n的答案都输出 比赛的时候想的有点偏,然后写了个nlog^2n的做法,T ...

随机推荐

  1. 配置ssh互信

    配置基于密钥认证的免密登录 用到的命令: ssh-keygen:创建公钥和密钥,会生成id_rsa和id_rsa.pub两个文件 生成ssh密钥后,密钥将默认存储在家目录下的.ssh/目录中.私钥和公 ...

  2. [转]Nginx介绍-反向代理、负载均衡

    原文:https://www.cnblogs.com/wcwnina/p/8728391.html 作者:失恋的蔷薇 1. Nginx的产生 没有听过Nginx?那么一定听过它的"同行&qu ...

  3. 动态修改HttpServletRequest的Post请求参数

    需求场景: 公司对APP调用的后台接口有个公用格式如下,外层包含了一些设备.版本.签名信息,主要的业务参数是在body里,外层信息都是在网关解决,验证签名后,在转发body到后台服务. { " ...

  4. 2020重新出发,JAVA入门,关键字&保留字

    关键字 & 保留字 关键字(或者保留字)是对编译器有特殊意义的固定单词,不能在程序中做其他目的使用. 关键字具有专门的意义和用途,和自定义的标识符不同,不能当作一般的标识符来使用.例如, cl ...

  5. 2020-04-13:怎么在日志里排查错误,该用哪些Linux命令

    能通过less命令打开文件,通过Shift+G到达文件底部,再通过?+关键字的方式来根据关键来搜索信息. 能通过grep的方式查关键字,具体用法是, grep 关键字 文件名,如果要两次在结果里查找的 ...

  6. C#LeetCode刷题之#110-平衡二叉树(Balanced Binary Tree)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4074 访问. 给定一个二叉树,判断它是否是高度平衡的二叉树. 本 ...

  7. C#LeetCode刷题之#263-丑数(Ugly Number)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3862 访问. 编写一个程序判断给定的数是否为丑数.丑数就是只包含 ...

  8. 用WindowsAPI实现文件复制功能

    用WindowsAPI实现文件复制功能 1. c代码 注释也在里面 文件名为 copyfile.c 运行出来的exe为 copyfile.exe #include <windows.h> ...

  9. ElasticSearch 7.X版本19个常用的查询语句

    整理一篇常用的CRUD查询语句,之前这篇文件是在17年左右发表的,从英文翻译过来,现在采用7.x 版本进行实验,弃用的功能或者参数,我这边会进行更新,一起来学习吧. 为了演示不同类型的 Elastic ...

  10. Caused by: org.postgresql.util.PSQLException: 错误: 语法错误 在 "desc" 、语法错误 在 "from" 附近

    此错误一般是由于postgres的数据库表字段名定义与关键字重名所致: 如下,创建的数据库表包含名称为“desc”的字段与倒叙查询的desc关键字冲突会导致Caused by: org.postgre ...