[CF474F]

题意:多次询问区间[l,r]中不是lca(xl...xr)的数的个数

先用线段树找出区间lca,然后用可持久化trie统计区间中是lca的数有多少个

 1 #include<stdio.h>
 2 #define loga 29
 3 int tot,M,Tgcd[300000],root[100010],ch[4000000][2],size[4000000];
 4 int gcd(int a,int b){
 5     if(a==0){
 6         if(b==0)return 0;
 7         return b;
 8     }
 9     if(b==0)return a;
10     if(a%b==0)return b;
11     return gcd(b,a%b);
12 }
13 int querygcd(int s,int t){
14     int ans=Tgcd[s+M];
15     for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){
16         if(~s&1)ans=gcd(ans,Tgcd[s^1]);
17         if(t&1)ans=gcd(ans,Tgcd[t^1]);
18     }
19     return ans;
20 }
21 void insert(int lroot,int rroot,int v,int p){
22     size[rroot]=size[lroot]+1;
23     if(p<0)return;
24     ch[rroot][((v>>p)&1)^1]=ch[lroot][((v>>p)&1)^1];
25     tot++;
26     ch[rroot][(v>>p)&1]=tot;
27     insert(ch[lroot][(v>>p)&1],ch[rroot][(v>>p)&1],v,p-1);
28 }
29 int querynum(int lroot,int rroot,int v,int p){
30     if(p<0)return size[rroot]-size[lroot];
31     if(ch[rroot][(v>>p)&1]==0)return 0;
32     return querynum(ch[lroot][(v>>p)&1],ch[rroot][(v>>p)&1],v,p-1);
33 }
34 int main(){
35     int n,m,i,j;
36     scanf("%d",&n);
37     for(M=1;M<n+2;M<<=1);
38     for(i=1;i<=n;i++){
39         scanf("%d",Tgcd+M+i);
40         tot++;
41         root[i]=tot;
42         insert(root[i-1],root[i],Tgcd[M+i],loga);
43     }
44     for(i=M-1;i>0;i--)Tgcd[i]=gcd(Tgcd[i<<1],Tgcd[i<<1|1]);
45     scanf("%d",&m);
46     while(m--){
47         scanf("%d%d",&i,&j);
48         printf("%d\n",j-i+1-querynum(root[i-1],root[j],querygcd(i,j),loga));
49     }
50 }
时间: 2024-10-23 01:00:01

[CF474F]的相关文章

CF 474/F, 线段树 + 一点数学

啊回家真是颓,一周了什么都没做 题目大意:给出一坨数,每次询问区间当中有多少个数能把其他区间内的所有数整除 解:由于我是知道这个是线段树专题,所以一开始就奔着gcd去了,想了一下还真是gcd,因为如果一个数a能整除另一个数b,那么gcd(a,b)一定为a,所以这说明可以做区间加法,直接上线段树就是,询问个数的时候还傻叉地想了一会,后面发现给每个线段记一下当前线段表示的gcd有几个就行,合并直接合并(可以证明现在这个线段的gcd一定是作为最优的取值,因为没有数等于这个gcd说明没有数能整除当前区间