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. window.location.href 和self.location的区别

    你从字面上就可以理解到 window 指的是当前窗口 而 self 指的是自己 在HTML 中 由于页面可以镶嵌页面 所以这2个就有了 区别 比如说 我有个页面A.HTML 里面嵌套了一个B.HTML ...

  2. java关键字 (jdk6),各自的含义是什么?

    Abstract 抽象的 一个Java语言中的关键字,用在类的声明中来指明一个类是不能被实例化的,但是可以被其它类继承.一个抽象类可以使用抽象方法,抽象方法不需要实现,但是需要在子类中被实现. bre ...

  3. 完整版的strcpy函数

    char *strcpy(char *strDest,const char *strSrc) { assert((strDest!=NULL) && (strSrc!=NULL)); ...

  4. Android 用ListView实现GridView分列显示

    我想实现百度影音首页的这种效果: 在网上用ScrollView+GridView可以实现,但是touch scrollview的时候会莫名刷新gridview,这样用户体验很不好,而且感觉百度不是这样 ...

  5. Poweroff – 很好很强大的定制关机工具

    Poweroff – 很好很强大的定制关机工具 Poweroff 是一个用来管理电脑关机系统的小工具,支持定时,支持远程 作者开放源代码,有兴趣的同学可以尝试着制作一下汉化版本.   可以设定不同时间 ...

  6. linux 命令行更新sdk

    ./android list sdk --proxy-host android-mirror.bugly.qq.com --proxy-port 8080 --no-ui -a -s ./androi ...

  7. tomcat+mysql数据库连接池的操作

    使用tomcat中的context.xml设置连接池 打开文件:Apache Software Foundation\Tomcat 6.0\conf\context.xml <Resource ...

  8. Ubuntu12.04 下安装QQ

    1:点此下载DEB安装包http://www.longene.org/download/WineQQ2012-20120712-Longene.deb 2:打开终端输入到目录中运行命令安装. sudo ...

  9. IntelliJ Idea取消Could not autowire. No beans of 'xxxx' type found的错误提示

    1.问题描述 在Idea的spring工程里,经常会遇到Could not autowire. No beans of 'xxxx' type found的错误提示.但程序的编译和运行都是没有问题的, ...

  10. Linux标准输入、输出和错误和文件重定向(转) --- good

    标准输入.输出和错误 当我们在shell中执行命令的时候,每个进程都和三个打开的文件相联系,并使用文件描述符来引用这些文件.由于文件描述符不容易记忆,shell同时也给出了相应的文件名.下面就是这些文 ...