题目描述
Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题。
对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数。
为了方便,我们规定妹子们的美丽度全都在[1,n]中。
给定一个长度为n(1≤n≤100000)的正整数序列s(1≤si≤n),对于m(1≤m≤1000000)次询问l,r,a,b
,每次输出sl⋯sr中,权值∈[a,b]的权值的种类数。
输入输出格式
输入格式:
第一行包括两个整数n,m(1≤n≤100000,1≤m≤1000000),表示数列s中的元素数和询问数。
第二行包括n个整数s1…sn(1≤si≤n)。
接下来m行,每行包括4个整数l,r,a,b(1≤l≤r≤n,1≤a≤b≤n),意义见题目描述。
保证涉及的所有数在C++的int内。保证输入合法。
输出格式:
对每个询问,单独输出一行,表示sl⋯sr中权值∈[a,b]的权值的种类数。
输入输出样例
10 10
4 4 5 1 4 1 5 1 2 1
5 9 1 2
3 4 7 9
4 4 2 5
2 3 4 7
5 10 4 4
3 9 1 1
1 4 5 9
8 9 3 3
2 2 1 6
8 9 1 4
2
0
0
2
1
1
1
0
1
2
说明
【样例的部分解释】
5 9 1 2
子序列为4 1 5 1 2
在[1,2]里的权值有1,1,2,有2种,因此答案为2。
3 4 7 9
子序列为5 1
在[7,9]里的权值有5,有1种,因此答案为1。
4 4 2 5
子序列为1
没有权值在[2,5]中的,因此答案为0。
2 3 4 7
子序列为4 5
权值在[4,7]中的有4,5,因此答案为2。
建议使用输入/输出优化。
Solution:
本题根号过1e6的莫队,神奇~。
本题需要求的是区间在值域范围内的种类数。
我们直接离线做莫队,记录下每个块的左右边界(由于值域和操作区间范围都是$[1,n]$,所以分一次块就够了),统计每次指针变换后的每个块内元素出现的种类数,那么对于查询$(l,r,a,b)$,先把指针移到区间$[l,r]$(这里块按下标),累加$a$到$b$的所在块(这里块按值域)之间出现的种类数就好了。
时间复杂度$O((n+m)sqrt n)$(我也不知道怎么能过~)。
代码:
/*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,s[N],tot[N]; int sum[5005],bl[N],ln[N],rn[N],ans[N*10]; 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*10]; 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){if((++tot[v])==1)sum[bl[v]]++;} il void del(int v){if(!(--tot[v]))sum[bl[v]]--;} il int query(int a,int b){ int l=bl[a],r=bl[b],res=0; for(RE int i=l+1;i<r;i++) res+=sum[i]; if(l==r) For(i,a,b) res+=(tot[i]>0); else { For(i,a,rn[l]) res+=(tot[i]>0); For(i,ln[r],b) res+=(tot[i]>0); } return res; } int main(){ n=gi(),m=gi();int blo=sqrt(n); For(i,1,n) s[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(s[l]),l++; while(l>q[i].l) l--,add(s[l]); while(r<q[i].r) r++,add(s[r]); while(r>q[i].r) del(s[r]),r--; ans[q[i].id]=query(q[i].a,q[i].b); } For(i,1,m) printf("%d ",ans[i]); return 0; }