莫队+分块+树状数组 【Ahoi2013】 作业 bzoj3236

3 篇文章 0 订阅

题目大意:
给定一个长度为n的序列,m个询问,询问一段区间内大于等于a小于等于b的数的个数和数值的个数。
n=1e5,m=1e6

题目分析:
看到大于等于a小于等于b这个条件,我们可以想到用树状数组来维护区间内比每个数字小的数的个数(数值同理,判断一下就好惹),每次修改都是logn的,并且可以发现,在原有的序列中新加入或减去一个数字,只需要一次修改,也就符合了莫队算法需要的知道[l,r]的答案,就能快速得到[l+1,r],[l-1,r],[l,r+1],[l,r-1]的答案的性质。但是询问数仍然很大,所以我们考虑分块,把时间复杂度降一个根号,就过了。
时间复杂度O(msqrt(n)logn)

不过我写的莫队真是很辣鸡啊,华丽丽地卡了评测……
这里写图片描述

代码如下:

#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 120000
#define M 1200000
using namespace std;
struct query{
    int l,r,a,b,num;
    bool operator < (const query&) const;
}q[M];

int n,m,blocks;
int a[N],belong[N];
int c[N],d[N],cnt[N];
int ans1[M],ans2[M];

int lowbit(int c) {return c&-c;}
bool query :: operator < (const query &c) const{
    return belong[l]<belong[c.l] || (belong[l]==belong[c.l] && r<c.r);
}

void update(int x,int y)
{
    cnt[x]+=y;
    for(int t=x;t<=n;t+=lowbit(t)) c[t]+=y;
    if((y==1 && cnt[x]==1) || (y==-1 && cnt[x]==0) )
        for(int t=x;t<=n;t+=lowbit(t)) d[t]+=y;
    return;
}
void query(int a,int b,int &ans1,int &ans2)
{
    for(;b;b-=lowbit(b))      ans1+=c[b],ans2+=d[b];
    for(a=a-1;a;a-=lowbit(a)) ans1-=c[a],ans2-=d[a];
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++) scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b),q[i].num=i;
    blocks=(int)ceil(sqrt(n));
    for(int i=1;i<=n;i++) belong[i]=(i-1)/blocks+1;
    sort(q+1,q+1+m);
    int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        while(r<q[i].r) update(a[++r], 1);
        while(r>q[i].r) update(a[r--],-1);
        while(l<q[i].l) update(a[l++],-1);
        while(l>q[i].l) update(a[--l], 1);
        query(q[i].a,q[i].b,ans1[q[i].num],ans2[q[i].num]);
    }
    for(int i=1;i<=m;i++) printf("%d %d\n",ans1[i],ans2[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值