P4867 Gty的二逼妹子序列
題目描述
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]的權值的種類數。
輸入輸出樣例
輸入樣例#1: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
輸出樣例#1:
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\n",ans[i]); return 0; }