This problem can be solve in simpler O(NsqrtN) solution, but I will describe O(NlogN) one.

We will solve this problem in offline. For each x (0 ≤ x < n) we
should keep all the queries that end in x. Iterate that x from
0 to n - 1. Also we need to keep some array D such
that for current x Dl + Dl + 1 + ... + Dx will
be the answer for query [l;x]. To keep D correct,
before the processing all queries that end in x, we need to update D.
Let t be the current integer in A,
i. e. Ax,
and vector P be the list of indices of previous occurences of t (0-based
numeration of vector). Then, if |P| ≥ t, you need to add 1 to DP[|P| - t],
because this position is now the first (from right) that contains exactly t occurences
of t. After that, if |P| > t,
you need to subtract 2 from DP[|P| - t - 1],
in order to close current interval and cancel previous. Finally, if |P| > t + 1, then you need additionally add 1 to DP[|P| - t - 2] to
cancel previous close of the interval.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std; #define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define ull unsigned long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdout) const int MAXN = 1e5+100;
int n,m; int a[MAXN],c[MAXN],ans[MAXN];
struct Query
{
int l,r,id;
bool operator < (const Query &t) const {return r<t.r;}
}q[MAXN];
inline int lowbit(int x){return x&(-x);}
void add(int i, int v)
{
while(i<=n)
{
c[i]+=v;
i+=lowbit(i);
}
}
int sum(int x)
{
int ret=0;
while(x>0)
{
ret+=c[x];
x-=lowbit(x);
}
return ret;
} int main()
{
int sz;
while(~scanf("%d%d",&n,&m))
{
vector<int>data[MAXN];
CL(c,0);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+1+m);
for(int i=1,k=1;i<=n;i++)
{
if(a[i]<=n)
{
data[a[i]].push_back(i);
sz=data[a[i]].size();
if(sz>=a[i])
{
add(data[a[i]][sz-a[i]],1);
if(sz>a[i])add(data[a[i]][sz-a[i]-1],-2);
if(sz>a[i]+1)add(data[a[i]][sz-a[i]-2],1);
}
}
while(q[k].r==i && k<=m)
{
ans[q[k].id]=sum(q[k].r)-sum(q[k].l-1);
k++;
}
} for(int i=1;i<=m;i++)
printf("%d\n",ans[i]); }
return 0;
}

用于调试理解的及及加了凝视的代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std; #define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define ull unsigned long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdout) const int MAXN = 1e5+100;
int n,m; int a[MAXN],c[MAXN],ans[MAXN];
struct Query
{
int l,r,id;
bool operator < (const Query &t) const {return r<t.r;}
}q[MAXN];
inline int lowbit(int x){return x&(-x);}
void add(int i, int v)
{
while(i<=n)
{
c[i]+=v;
i+=lowbit(i);
}
}
int sum(int x)
{
int ret=0;
while(x>0)
{
ret+=c[x];
x-=lowbit(x);
}
return ret;
} int main()
{
int sz;
while(~scanf("%d%d",&n,&m))
{
vector<int>data[MAXN];
CL(c,0);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+1+m);
for(int i=1,k=1;i<=n;i++)
{
if(a[i]<=n)
{
data[a[i]].push_back(i);
sz=data[a[i]].size();
if(sz>=a[i])
{
add(data[a[i]][sz-a[i]],1);//从右往左第a[i]次出现a[i]的位置+1
if(sz>a[i])add(data[a[i]][sz-a[i]-1],-2);
//从右往左第a[i]+1次出现a[i]的位置 -2,
//由于当Sz==a[i]的时候,这个位置已经被加过1。此次读到i的时候。
//从右往左第a[i]次出现a[i]的位置也被+1。
//那么查询第a[i]+1次出现a[i]的位置到i。答案就是-2+1+1=0,
//查询第a[i]次出现a[i]的位置到i,答案就是1
if(sz>a[i]+1)add(data[a[i]][sz-a[i]-2],1);
//从右往左第a[i]+2次出现a[i]的位置 +1,之前被+1-2,所以变成0
//这三行代码维护出来,从当前的i往左数,第a[i]次出现a[i]的位置总是1
//第a[i]+1次出现a[i]的位置总是-1,第a[i]+2及很多其它次的位置总是0,这样以i为右端点的区间的查询结果就都对了
}
}
while(q[k].r==i && k<=m)
{
/////////////
printf("#i=%d#\n",i);
for(int j=0;j<=n;j++)
printf("c[%d]=%d\n",j,c[j]);
//////////////
ans[q[k].id]=sum(q[k].r)-sum(q[k].l-1);
k++;
}
} for(int i=1;i<=m;i++)
printf("%d\n",ans[i]); }
return 0;
}

Codeforces 220B - Little Elephant and Array 离线树状数组的更多相关文章

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

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

  2. Codeforces 703D Mishka and Interesting sum 离线+树状数组

    链接 Codeforces 703D Mishka and Interesting sum 题意 求区间内数字出现次数为偶数的数的异或和 思路 区间内直接异或的话得到的是出现次数为奇数的异或和,要得到 ...

  3. CodeForces - 220B Little Elephant and Array (莫队+离散化 / 离线树状数组)

    题意:N个数,M个查询,求[Li,Ri]区间内出现次数等于其数值大小的数的个数. 分析:用莫队处理离线问题是一种解决方案.但ai的范围可达到1e9,所以需要离散化预处理.每次区间向外扩的更新的过程中, ...

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

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

  5. POJ 3416 Crossing --离线+树状数组

    题意: 给一些平面上的点,然后给一些查询(x,y),即以(x,y)为原点建立坐标系,一个人拿走第I,III象限的点,另一个人拿II,IV象限的,点不会在任何一个查询的坐标轴上,问每次两人的点数差为多少 ...

  6. HDU 2852 KiKi's K-Number(离线+树状数组)

    题目链接 省赛训练赛上一题,貌似不难啊.当初,没做出.离线+树状数组+二分. #include <cstdio> #include <cstring> #include < ...

  7. CF #365 (Div. 2) D - Mishka and Interesting sum 离线树状数组

    题目链接:CF #365 (Div. 2) D - Mishka and Interesting sum 题意:给出n个数和m个询问,(1 ≤ n, m ≤ 1 000 000) ,问在每个区间里所有 ...

  8. CF #365 (Div. 2) D - Mishka and Interesting sum 离线树状数组(转)

    转载自:http://www.cnblogs.com/icode-girl/p/5744409.html 题目链接:CF #365 (Div. 2) D - Mishka and Interestin ...

  9. HDU3333 Turing Tree 离线树状数组

    题意:统计一段区间内不同的数的和 分析:排序查询区间,离线树状数组 #include <cstdio> #include <cmath> #include <cstrin ...

随机推荐

  1. sharepoint2013小技巧

    一.创建基于经典认证的应用程序 New-SPWebApplication -Name "Contoso Internet Site" -ApplicationPool " ...

  2. NotImplementedException未实现该方法或操作

    使用DevExpress为控件CheckedListBoxControl绑定DataSource时,引发异常“NotImplementedException未实现该方法或操作”,代码如下: this. ...

  3. Linux shell 脚本中”2>&1″的含义解释

    脚本是:nohup /mnt/Nand3/H2000G  >/dev/null  2>&1 &   对于& 1 更准确的说应该是文件描述符 1,而1 一般代表的就是 ...

  4. php遍历数据库

    数据库 <?php mysql_connect("localhost","root",""); mysql_set_charset(& ...

  5. ebay如何确定同一电脑登陆了多个账号,以及同一账号登陆过多台电脑

    转自hilton 的BLOG http://jimqu.blog.51cto.com/105370/654691 一切要从ebay的买家保护说起 ebay作为一个电子商务平台,之所以可以汇聚如此众多的 ...

  6. MySQL如何执行关联查询

    MySQL中‘关联(join)’ 一词包含的意义比一般意义上理解的要更广泛.总的来说,MySQL认为任何一个查询都是一次‘关联’ --并不仅仅是一个查询需要到两个表的匹配才叫关联,索引在MySQL中, ...

  7. nginx location详解(三)

    location官方文档:http://nginx.org/en/docs/http/ngx_http_core_module.html#location Syntax: location [ = | ...

  8. tcpdump使用和TCP/IP包分析

    关于tcpdump如何抓包,本文不再总结,可以查看 tcpdump的官方地址查看http://www.tcpdump.org 本文重点记录两个部分:           第一部分:tcpdump所抓包 ...

  9. ubuntu 引导删除

    点开始,在搜索中输入cmd,在搜到的cmd上右键以管理员身份运行,在打开的cmd中输入命令:bcdedit在命令结果中找到类似如下的版块: 实模式启动扇区---------------------标识 ...

  10. 【结构型】Bridge模式

    桥接模式是为了将对象的抽象与实现分离,使得它们可以独立变化.简简单单的一句话,却已经是站在了更高抽象层面上来看待.设计.解决问题.平常我们多是对具体问题进行分析.抽象,然后就开始设计,这对多数情况下基 ...