P4396 [AHOI2013]作业

题目描述

此时己是凌晨两点,刚刚做了Codeforces的小A掏出了英语试卷。英语作业其实不算多,一个小时刚好可以做完。然后是一个小时可以做完的数学作业,接下来是分别都是一个小时可以做完的化学,物理,语文......小A压力巨大。

这是小A碰见了一道非常恶心的数学题,给定了一个长度为n的数列和若干个询问,每个询问是关于数列的区间表示数列的第l个数到第r个数),首先你要统计该区间内大于等于a,小于等于b的数的个数,其次是所有大于等于a,小于等于b的,且在该区间中出现过的数值的个数。

小A望着那数万的数据规模几乎绝望,只能向大神您求救,请您帮帮他吧。

输入输出格式

输入格式:

第一行n,m

接下来n个数表示数列

接下来m行,每行四个数l,r,a,b

输出格式:

输出m行,分别对应每个询问,输出两个数,分别为在l到r这段区间中大小在[a,b]中的数的个数,以及大于等于a,小于等于b的,且在该区间中出现过的数值的个数(具体可以参考样例)。

输入输出样例

输入样例#1: 
3 4
1 2 2
1 2 1 3
1 2 1 1
1 3 1 3
2 3 2 3
输出样例#1: 
2 2
1 1
3 2
2 1

说明

N<=100000,M<=100000

 

Solution:

  本题是上题妹子序列的加强版?反正还是莫队。

  第二问就是上题的询问(只不过数据弱化了),第一问也很简单,只需要在分块时多维护一下值域范围内的数的个数,其它就是一些细节问题的处理了。

代码:

/*Code by 520 -- 10.4*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=100005;
int n,m,a[N],ln[N],rn[N];
int sum[5005],ppx[5005],c[N],bl[N],ans[N][2];
struct node{
    int l,r,a,b,id;
    bool operator < (const node &a) const {return bl[l]==bl[a.l]?r<a.r:l<a.l;}
}q[N];

int gi(){
    int a=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;
}

il void add(int v){ppx[bl[v]]++,sum[bl[v]]+=((++c[v])==1);}

il void del(int v){ppx[bl[v]]--,sum[bl[v]]-=((--c[v])==0);}

il void query(node x){
    int l=bl[x.a],r=bl[x.b],res1=0,res2=0;
    for(RE int i=l+1;i<r;i++) res1+=ppx[i],res2+=sum[i];
    if(l==r) For(i,x.a,x.b) res1+=c[i],res2+=(c[i]>0);
    else {
        For(i,x.a,rn[l]) res1+=c[i],res2+=(c[i]>0);
        For(i,ln[r],x.b) res1+=c[i],res2+=(c[i]>0);
    }
    ans[x.id][0]=res1,ans[x.id][1]=res2;
}

int main(){
    n=gi(),m=gi(); int blo=sqrt(n);
    For(i,1,n) a[i]=gi(),bl[i]=(i-1)/blo+1;
    For(i,1,n) {
        rn[bl[i]]=i;
        if(!ln[bl[i]]) ln[bl[i]]=i;
    }
    For(i,1,m) q[i]=node{gi(),gi(),gi(),gi(),i};
    sort(q+1,q+m+1);
    for(RE int i=1,l=1,r=0;i<=m;i++){
        while(l<q[i].l) del(a[l]),++l;
        while(l>q[i].l) --l,add(a[l]);
        while(r<q[i].r) ++r,add(a[r]);
        while(r>q[i].r) del(a[r]),--r;
        query(q[i]);
    }
    For(i,1,m) printf("%d %d\n",ans[i][0],ans[i][1]);
    return 0;
}

 

 

转载于:https://www.cnblogs.com/five20/p/9792231.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值