题意:N个数,M个查询,求[Li,Ri]区间内出现次数等于其数值大小的数的个数。

分析:用莫队处理离线问题是一种解决方案。但ai的范围可达到1e9,所以需要离散化预处理。每次区间向外扩的更新的过程中,检查该位置的数ai的出现次数是否已经达到ai或ai+1,以判断是否要更新结果。同理,区间收缩的时候判断ai出现次数是否达到ai或ai-1。

另一种更高效的方法是使用树状数组离线处理查询。用一个vector数组维护每个ai以此出现的位置。显然ai>N的数不会对结果做出贡献,所以数组开1e5就足够了。树状数组的维护操作:从1道N递推,当ai的出现次数sz>=ai后,对其从右往左数的第ai次出现的位置+1;当出现次数sz>ai次后,需要对从右往左数第ai+1的位置减2;但是出现次数sz>ai+1次后,上述操作会多减去一部分,那么相应的就应该在从右往左数第ai+2次出现的位置上+1。

莫队代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
const int maxn=1e5+;
typedef long long LL;
int N,M,res;
struct Node{
int val;
int id;
bool operator < (const Node &p) const {return val<p.val;}
}a[maxn];
bool cmpid(const Node &x,const Node &y) {return x.id<y.id;} int b[maxn];
int pos[maxn],cnt[maxn],block; //块数
int ans[maxn];
int v[maxn]; //离散化
struct Query{
int L,R,id;
}Q[maxn];
bool cmp1(const Query& x,const Query& y){ //根据所属块的大小排序
if(pos[x.L]==pos[y.L]) return x.R<y.R;
return pos[x.L]<pos[y.L];
} void add(int pos)
{
int id = v[a[pos].id];
if(cnt[id]==b[pos]-) res++;
else if(cnt[id]==b[pos]) res--;
cnt[id]++;
} void pop(int pos)
{
int id = v[a[pos].id];
if(cnt[id]==b[pos]) res--;
else if(cnt[id]==b[pos]+) res++;
cnt[id]--;
} //#define LOCAL
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T;
int cas=;
while(scanf("%d%d",&N,&M)==){
block = ceil(sqrt(1.0*N));
memset(cnt,,sizeof(cnt));
for(int i=;i<=N;++i){
scanf("%d",&a[i].val);
a[i].id = i;
b[i] = a[i].val;
pos[i]=i/block;
}
//离散化
sort(a+,a+N+);
int tag = ;
v[a[].id] = tag;
for(int i=;i<=N;++i){
if(a[i].val == a[i-].val) v[a[i].id] = tag;
else v[a[i].id] = ++tag;
}
sort(a+,a+N+,cmpid); for(int i=;i<=M;++i){
scanf("%d%d",&Q[i].L,&Q[i].R);
Q[i].id = i;
}
sort(Q+,Q+M+,cmp1);
res=;
int curL=,curR=;
for(int i=;i<=M;++i){
while(curL>Q[i].L) add(--curL);
while(curR<Q[i].R) add(++curR);
while(curL<Q[i].L) pop(curL++);
while(curR>Q[i].R) pop(curR--);
ans[Q[i].id] = res;
}
for(int i=;i<=M;++i)
printf("%d\n",ans[i]);
}
return ;
}

离线树状数组代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
using namespace std;
const int maxn=1e5+;
typedef long long LL;
int N,M;
int a[maxn];
int ans[maxn];
struct Query{
int L,R,id;
bool operator < (const Query &q) const {return R<q.R;}
}Q[maxn]; int bit[maxn];
inline int lowbit(int x) {return x&(-x);} void add(int i,int val){
for(;i<=N;i+=lowbit(i)) bit[i]+=val;
} int sum(int i){
int res=;
for(;i>;i-=lowbit(i)) res+=bit[i];
return res;
} #define LOCAL
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T;
int cas=;
while(scanf("%d%d",&N,&M)==){
vector<int> pos[maxn];
memset(bit,,sizeof(bit));
for(int i=;i<=N;++i){
scanf("%d",&a[i]);
} for(int i=;i<=M;++i){
scanf("%d%d",&Q[i].L,&Q[i].R);
Q[i].id = i;
}
sort(Q+,Q+M+); int la=;
for(int i=;i<=N;++i){
if(a[i]<=N){ //如果a[i]>N 那么不可能对结果有贡献
pos[a[i]].push_back(i); //记录出现的位置
int sz = pos[a[i]].size();
if(sz>=a[i]){
add(pos[a[i]][sz-a[i]],); //对从右往左数的第a[i]次出现的位置,加1
//若a[i]出现的次数大于a[i],从右往左数出现的第a[i]+1次的位置已经被加1,不能作出贡献的前缀被多加了2,所以减去2
if(sz>a[i]) add(pos[a[i]][sz-a[i]-],-);
//但是若a[i]出现的次数大于a[i]+1,那么之前的-2操作就需要“补偿回来”
if(sz>a[i]+) add(pos[a[i]][sz-a[i]-],);
}
}
while(la<=M && Q[la].R==i){
ans[Q[la].id] = sum(Q[la].R) - sum(Q[la].L-);
la++;
}
if(la>M) break;
}
for(int i=;i<=M;++i)
printf("%d\n",ans[i]);
}
return ;
}

CodeForces - 220B Little Elephant and Array (莫队+离散化 / 离线树状数组)的更多相关文章

  1. codeforces 220B . Little Elephant and Array 莫队+离散化

    传送门:https://codeforces.com/problemset/problem/220/B 题意: 给你n个数,m次询问,每次询问问你在区间l,r内有多少个数满足其值为其出现的次数 题解: ...

  2. CodeForces - 375D Tree and Queries (莫队+dfs序+树状数组)

    You have a rooted tree consisting of n vertices. Each vertex of the tree has some color. We will ass ...

  3. 【序列莫队+二分答案+树状数组】POJ2104-K-th Number

    [题目大意] 给出一个长度为n的序列和m组查询(i,j,k),输出[i,j]中的第k大数. [思路] 先离散化然后莫队分块.用树状数组来维护当前每个值的个数,然后对于每次询问二分答案即可. 又一次实力 ...

  4. SPOJ DQUERY - D-query (莫队算法|主席树|离线树状数组)

    DQUERY - D-query Given a sequence of n numbers a1, a2, ..., an and a number of d-queries. A d-query ...

  5. Educational Codeforces Round 10 D. Nested Segments 离线树状数组 离散化

    D. Nested Segments 题目连接: http://www.codeforces.com/contest/652/problem/D Description You are given n ...

  6. Codeforces Round #365 (Div. 2) D - Mishka and Interesting sum(离线树状数组)

    http://codeforces.com/contest/703/problem/D 题意: 给出一行数,有m次查询,每次查询输出区间内出现次数为偶数次的数字的异或和. 思路: 这儿利用一下异或和的 ...

  7. Codeforces Round #510 (Div. 2) D. Petya and Array(离散化+反向树状数组)

    http://codeforces.com/contest/1042/problem/D 题意 给一个数组n个元素,求有多少个连续的子序列的和<t (1<=n<=200000,abs ...

  8. Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum (离线树状数组+前缀xor)

    题目链接:http://codeforces.com/contest/703/problem/D 给你n个数,m次查询,每次查询问你l到r之间出现偶数次的数字xor和是多少. 我们可以先预处理前缀和X ...

  9. Codeforces Round #229 (Div. 2) C. Inna and Candy Boxes 树状数组s

    C. Inna and Candy Boxes   Inna loves sweets very much. She has n closed present boxes lines up in a ...

随机推荐

  1. bjposition

    背景位置:background-origin:content-box;//"border-box", "padding-box", "content- ...

  2. 如何在ChemDraw 15.1 Pro中添加模板

    ChemDraw化学绘图工具为了方便用户的使用,特地开发了众多的各种类型模板.用户在绘制一些简单或复杂的化学结构式时,可以直接从ChemDraw模板库里直接调用使用,虽然ChemDraw模板非常的丰富 ...

  3. 第七篇:使用 fcntl 函数 获取,设置文件的状态标志

    前言 当打开一个文件的时候,我们需要指定打开文件的模式( 只读,只写等 ).那么在程序中如何获取,修改这个文件的状态标志呢? 本文将告诉你如何用 fcntl函数 获取指定文件的状态标志. 解决思路 1 ...

  4. Android开发:《Gradle Recipes for Android》阅读笔记(翻译)4.4——自定义代码集合

    问题: 你想要在项目中使用非标准的代码目录. 解决方案: 在gradle的build配置里面使用sourceSets属性. 讨论: Android分发的samples里面使用多个代码目录,使得通用的文 ...

  5. C语言数据类型大小

    数据类型大小是由操作系统和编译器共同决定的,但必须满足: short和int至少为16bit:long至少为32bit: short不能超过int,int不能超过long. 在主流编译器中,32位机和 ...

  6. [LintCode] A + B 问题

    Bit-by-Bit summation: class Solution { public: /* * @param a: The first integer * @param b: The seco ...

  7. Less-mixin判断(守卫)二

    mixin卫士--判断 或与且语法 且:()and() 或:(),() --且 examlpe: .test(@a) when (isNumber(@a)) and (@a>=5){ font- ...

  8. CodeForces 17E Palisection(回文树)

    E. Palisection time limit per test 2 seconds memory limit per test 128 megabytes input standard inpu ...

  9. Scala 常用语法

    Clojure首先是FP, 但是由于基于JVM, 所以不得已需要做出一些妥协, 包含一些OO的编程方式 Scala首先是OO, Java语法过于冗余, 一种比较平庸的语言, Scala首先做的是简化, ...

  10. Python WSGI v1.0 中文版(转)

    add by zhj: WSGI全称Web Server Gateway Interface,即Web网关接口.其实它并不是OSI七层协议中的协议,它就是一个接口而已,即函数,而WSGI规定了该接口的 ...