CF #136Div2 D. Little Elephant and Array

来源:互联网 发布:网站美工 编辑:程序博客网 时间:2024/06/05 16:39

                                               D. Little Elephant and Array


time limit per test4 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
The Little Elephant loves playing with arrays. He has array a, consisting of n positive integers, indexed from 1 to n. Let's denote the number with index i as ai.

Additionally the Little Elephant has m queries to the array, each query is characterised by a pair of integers lj and rj (1 ≤ lj ≤ rj ≤ n). For each query lj, rj the Little Elephant has to count, how many numbers x exist, such that number x occurs exactly x times among numbers alj, alj + 1, ..., arj.

Help the Little Elephant to count the answers to all queries.

Input
The first line contains two space-separated integers n and m (1 ≤ n, m ≤ 105) — the size of array a and the number of queries to it. The next line contains n space-separated positive integers a1, a2, ..., an (1 ≤ ai ≤ 109). Next m lines contain descriptions of queries, one per line. The j-th of these lines contains the description of the j-th query as two space-separated integers lj and rj (1 ≤ lj ≤ rj ≤ n).

Output
In m lines print m integers — the answers to the queries. The j-th line should contain the answer to the j-th query.

Sample test(s)
input
7 2
3 1 2 2 3 3 7
1 7
3 4
output
3
1


题意:问在一段区间内有多少个数它本身的值和它出现的次数相同

思路:用线段树思想,成段更新,单点求值

由于是单点求和,所以采用松弛操作,向下更新子节点的值(lazy思想)-----因为往下才有l==r

对询问离线处理,对于每一个数x,当找到x个x时,那么以1到x第一次出现的位置i 即[1,i]这一段区间的人一多为起点,其所求个数都加1,当往右走,出现x+1个x时,前面[1,i]要更新减1,而在[i+1,j] 加1, j为第(x+1-x+1)个x的位置

看例子:

3 1 2 2 3 3 7 3

当找到1个1时即指针指向下标p=2,  [1,2]区间+1,2为1第一次出现的位置

当找到2个2时即指针指向下标p=4,  [1,3]区间+1

当找到3个3时即指针指向下标p=6,  [1,1]区间+1

当找到4个3时即指针指向下标p=8,  [1,1]区间-1, [2,5]区间+1,5为第(4-3+1)=2个3出现的位置

代码:

#include <iostream>//D#include <stdio.h>#include <cmath>#include <cstring>#include <algorithm>#include <vector>#include <queue>using namespace std;#define lson l,mid,2*num#define rson mid+1,r,2*num+1const int N=1e5+5;struct Query{    int s,e;    int pos;} q[N];bool cmp(Query a,Query b){    return a.e < b.e;}vector<int>V[N];//记录每一个值x出现的位置int n,m;int a[N],cnt[N];//cnt[N]记录x出现的次数int pre[N][2];//记录前一个已经更新了的区间int ans[N];int sum[4*N];void relax(int num)//松弛操作{    int &s=sum[num];    sum[num<<1]+=sum[num];    sum[num<<1|1]+=sum[num];    s=0;}void PushUp(int num){    sum[num]=sum[num<<1]+sum[num<<1|1];}void build(int l,int r,int num){    if(l==r)return;    int mid=(l+r)/2;    build(lson);    build(rson);}void update(int L,int R,int l,int r,int num,int add){    if(L<=l && R>=r)    {        sum[num]+=add;        return;    }    relax(num);    int mid=(l+r)/2;    if(L<=mid)update(L,R,lson,add);    if(R>mid)update(L,R,rson,add);}int query(int pos,int l,int r,int num){    if(l==r)return sum[num];    relax(num);    int mid=(l+r)/2;    if(pos<=mid)return query(pos,lson);    else    return query(pos,rson);}int main(){    scanf("%d%d",&n,&m);    for(int i=1; i<=n; i++)    {        scanf("%d",&a[i]);    }    build(1,n,1);    for(int i=1; i<=m; i++)    {        scanf("%d%d",&q[i].s,&q[i].e);        q[i].pos=i;    }    sort(q+1,q+m+1,cmp);    memset(cnt,0,sizeof(cnt));    memset(sum,0,sizeof(sum));    int num=1;    for(int i=1; i<=n; i++)    {        int v=a[i];        if(v<=n)        {            cnt[v]++;            V[v].push_back(i);            if(cnt[v]==v)            {                pre[v][0]=1;                pre[v][1]=V[v][0];                update(pre[v][0],pre[v][1],1,n,1,1);            }            else if(cnt[v]>v)            {                update(pre[v][0],pre[v][1],1,n,1,-1);                pre[v][0]=pre[v][1]+1;                pre[v][1]=V[v][cnt[v]-v];//求第cnt[v]-v+1个x出现的位置                update(pre[v][0],pre[v][1],1,n,1,1);            }        }        while(q[num].e==i && num <= m)        {            ans[q[num].pos]=query(q[num].s,1,n,1);            num++;        }    }    for(int i=1; i<=m; i++)    {        printf("%d\n",ans[i]);    }    return 0;}


原创粉丝点击