bzoj3809: Gty的二逼妹子序列
Description
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]的权值的种类数。
Input
第一行包括两个整数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内。
保证输入合法。
Output
对每个询问,单独输出一行,表示sl...sr中权值∈[a,b]的权值的种类数。
Sample Input
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
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
Sample Output
2
0
0
2
1
1
1
0
1
2
0
0
2
1
1
1
0
1
2
HINT
样例的部分解释:
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。
建议使用输入/输出优化。
这题第一眼看上去是莫队+树状数组,但复杂度是O(M√N log N),会TLE
正确的姿势是对权值分块,这样使得每次查询复杂度变为O(√n),而修改的复杂度变为O(1)
这样总复杂度为O(M√N)
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 100005 7 using namespace std; 8 char ch; 9 int n,m,siz,s[maxn],cnt[maxn],sum[400],pos[maxn],ans[maxn*10]; 10 bool ok; 11 void read(int &x){ 12 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 13 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 14 if (ok) x=-x; 15 } 16 struct Query{ 17 int l,r,a,b,id; 18 void init(int i){read(l),read(r),read(a),read(b),id=i;} 19 }list[maxn*10]; 20 bool cmp(Query a,Query b){ 21 if (pos[a.l]!=pos[b.l]) return pos[a.l]<pos[b.l]; 22 return pos[a.r]<pos[b.r]; 23 } 24 void add(int col){ 25 cnt[col]++; 26 if (cnt[col]==1) sum[pos[col]]++; 27 } 28 void del(int col){ 29 cnt[col]--; 30 if (!cnt[col]) sum[pos[col]]--; 31 } 32 int query(int l,int r){ 33 int ans=0; 34 for (int i=pos[l]+1;i<pos[r];i++) ans+=sum[i]; 35 if (pos[l]!=pos[r]){ 36 for (int i=l;pos[i]==pos[l];i++) if (cnt[i]) ans++; 37 for (int i=r;pos[i]==pos[r];i--) if (cnt[i]) ans++; 38 } 39 else for (int i=l;i<=r;i++) if (cnt[i]) ans++; 40 return ans; 41 } 42 void work(){ 43 int l=1,r=0; 44 for (int i=1;i<=m;i++){ 45 for (;r<list[i].r;r++) add(s[r+1]); 46 for (;r>list[i].r;r--) del(s[r]); 47 for (;l<list[i].l;l++) del(s[l]); 48 for (;l>list[i].l;l--) add(s[l-1]); 49 ans[list[i].id]=query(list[i].a,list[i].b); 50 } 51 } 52 int len; 53 char ss[30]; 54 void write(int v){ 55 if (!v) putchar('0'); 56 for (len=0;v;v/=10) ss[++len]=(v%10)+'0'; 57 for (;len;len--) putchar(ss[len]); 58 putchar('\n'); 59 } 60 int main(){ 61 read(n),read(m),siz=(int)sqrt(n); 62 for (int i=1;i<=n;i++) read(s[i]); 63 for (int i=1;i<=m;i++) list[i].init(i); 64 for (int i=1;i<=n;i++) pos[i]=i/siz; 65 sort(list+1,list+m+1,cmp); 66 work(); 67 for (int i=1;i<=m;i++) write(ans[i]); 68 return 0; 69 }