[arc086e]snuke line
题意:
有n个区间,询问对于$1\leq i\leq m$的每个i,有多少个区间至少包含一个i的倍数?
$1\leq N\leq 3\times 10^5$
$1\leq M\leq 10^5$
题解:
开始就想到了调和级数的复杂度,但是一直没想到反着统计。。。
正着统计区间是否包含$i$的倍数很麻烦,不妨反过来统计是否不包含,那么不包含的情况肯定是区间卡在两个$i$的倍数之间或者在$\lfloor\frac{m}{i}\rfloor\times i$和$M$之间,用调和级数的时间复杂度可以把所有倍数搞出来。那么可以将询问离线,按照$i$的倍数分段,然后用树状数组维护即可。
调和级数一个$log$,树状数组一个$log$,所以最后的时间复杂度是$O(mlogmlogn)$
貌似有很多dalao用不同姿势的分块碾了过去QAQ
代码:
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<vector>
5 #include<cmath>
6 #define lb(x) (x&-x)
7 using namespace std;
8 struct task{
9 int x,id;
10 }a[2000001];
11 int n,m,l,r,tot=0,ans[2000001],t[2000001];
12 vector<int>g1[2000001],g2[2000001];
13 void add(int x,int v){
14 for(;x;x-=lb(x)){
15 t[x]+=v;
16 }
17 }
18 int query(int x){
19 int ret=0;
20 for(;x<=m;x+=lb(x)){
21 ret+=t[x];
22 }
23 return ret;
24 }
25 int main(){
26 scanf("%d%d",&n,&m);
27 for(int i=1;i<=n;i++){
28 scanf("%d%d",&l,&r);
29 g1[r].push_back(l);
30 }
31 for(int i=1;i<=m;i++){
32 ans[i]=n;
33 for(int j=1;j<=m/i;j++){
34 a[++tot].x=i*(j-1);
35 a[tot].id=i;
36 g2[i*j].push_back(tot);
37 }
38 a[++tot].x=(m/i)*i;
39 a[tot].id=i;
40 g2[m+1].push_back(tot);
41 }
42 for(int i=0;i<=m+1;i++){
43 for(int j=0,jj=g2[i].size();j<jj;j++){
44 ans[a[g2[i][j]].id]-=query(a[g2[i][j]].x+1);
45 }
46 for(int j=0,jj=g1[i].size();j<jj;j++){
47 add(g1[i][j],1);
48 }
49 }
50 for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
51 return 0;
52 }