NC19427-换个角度思考-(树状数组+离线处理||莫队算法)

https://ac.nowcoder.com/acm/problem/19427

题意:给出1e5个值为[1,1e5]的数组,查询1e5次[l,r]区间中的小于x(<=1e5)的数 的个数,1<=l<=r<=1e5。

思路:暴力必死

(1)树状数组+离线处理

所有数都是小于1e5,可以开一个树状数组c统计,对原数组离线处理,从小到大插入树状数组,对查询也离线处理,从小到大查询,对于每一个查询的x,将小于x的原数组元素先插入,后统计。由于都是从小到大,不会计算重复。时间复杂度O(m*logn),空间消耗较大。

(2)莫队裸题

(3)数据扩展

  • 将数据上限全部都增加到1e6,莫队超时,树状数组还是稳如老狗
  • 只将x增加到1e9甚至1e18,数组大小会爆,不能用树状数组,只能用莫队
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<set>
#define ll long long
#define inf 0x3f3f3f3f///负无穷小 -0x7f
using namespace std;

int n,m;
struct node
{
    int a;
    int idx;
};
node arr[100005];
struct query
{
    int l;
    int r;
    int x;
    int idx;
    int ans;
};
query q[100005];
int c[100005];///树状数组

bool cmp1(node p1,node p2)///对原数组插入顺序做出调整
{
    if(p1.a==p2.a)
        return p1.idx<p2.idx;
    return p1.a<p2.a;
}

bool cmp2(query q1,query q2)///查询离线处理,同步树状数组求和
{
    return q1.x<q2.x;
}

bool cmp3(query q1,query q2)///按顺序输出答案
{
    return q1.idx<q2.idx;
}

int lowbit(int x)
{
    return x&(-x);
}

void add(int x,int val)///在x的位置添加val值
{
    while(x<=n+1)
    {
        c[x]+=val;
        x+=lowbit(x);
    }
}

int sum(int x)///求前x的前缀和
{
    int res=0;
    while(x>0)
    {
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}


int main()///NC19427离线+树状数组
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&arr[i].a);
        arr[i].idx=i;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].x);
        q[i].idx=i;
    }
    sort(arr+1,arr+n+1,cmp1);
    sort(q+1,q+m+1,cmp2);
    int i=1,j=1;
    for(i=1;i<=m;i++)
    {
        for(;j<=n && arr[j].a<=q[i].x;j++)///把原数组中小于 查询的x 的插入树状数组
            add(arr[j].idx,1);
        q[i].ans=sum(q[i].r)-sum(q[i].l-1);
    }
    sort(q+1,q+m+1,cmp3);
    for(int i=1;i<=m;i++)
        printf("%d
",q[i].ans);
}
原文地址:https://www.cnblogs.com/shoulinniao/p/12888010.html