CF #271 F Ant colony 树

题目链接:http://codeforces.com/contest/474/problem/F

一个数组,每一次询问一个区间中有多少个数字可以整除其他所有区间内的数字。

能够整除其他所有数字的数一定是这些数字的gcd,所以可以用一个线段树来查询区间gcd。

接着需要统计区间内这个数字的出现个数,在读取数组时,顺便保存一个pair<int,int>键为数字,val为位置的数组,再sort一下,统计区间内某个数字出现次数,直接upper_bound-lower_bound即可。

 

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 #include <string>
 5 #include <string.h>
 6 #include <stdio.h>
 7 #include <math.h>
 8 #include <stdlib.h>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <set>
13 #include <ctime>
14 #include <numeric>
15 #include <cassert>
16 
17 using namespace std;
18 
19 const int N=1e5+10;
20 
21 int s[N];
22 pair<int,int> d[N];
23 int t[N<<2];
24 
25 int gcd(int a,int b){
26     if (b==0) return a;
27     return gcd(b,a%b);
28 }
29 void up(int rt) {
30     t[rt]=gcd(t[rt<<1],t[rt<<1|1]);
31 }
32 void build(int l,int r,int rt) {
33     if (l==r){
34         t[rt]=s[l];
35         return;
36     }
37     int m=(l+r)>>1;
38     build(l,m,rt<<1);
39     build(m+1,r,rt<<1|1);
40     up(rt);
41 }
42 int ask(int L,int R,int l,int r,int rt) {
43     if (L<=l&&r<=R) {
44         return t[rt];
45     }
46     int m=(l+r)>>1;
47     int ret=0,u=0,v=0;
48     if (L<=m)
49         u=ask(L,R,l,m,rt<<1);
50     if (R>m)
51         v=ask(L,R,m+1,r,rt<<1|1);
52     return gcd(u,v);
53 }
54 int main () {
55     int n;
56     scanf("%d",&n);
57     for (int i=1;i<=n;i++) {
58         scanf("%d",s+i);
59         d[i-1]=make_pair(s[i],i);
60     }
61     build(1,n,1);
62     sort(d,d+n);
63     int m;
64     scanf("%d",&m);
65     while (m--) {
66         int l,r;
67         scanf("%d %d",&l,&r);
68         int g=ask(l,r,1,n,1);
69         int u=lower_bound(d,d+n,make_pair(g,l))-d;
70         int v=lower_bound(d,d+n,make_pair(g,r+1))-d;
71         printf("%d\n",r-l+1-(v-u));
72         //printf("%d %d %d\n",g,u,v);
73     }
74     return 0;
75 }
View Code

 

posted @ 2016-03-05 18:32  活在夢裡  阅读(347)  评论(0编辑  收藏  举报