Hdu 4777 Rabbit Kingdom (树状数组)
题目链接:
题目描述:
有一个含有n个数的序列,m个询问。问 [l, r] 区间内与所有数都互质的数有几个?
解题思路:
先预处理出来每个数的贡献区间,每个数的贡献区间是 [左边最近不互质数的位置,右边最近不互质数的位置] ,现在问题就转化为了求区间 [L, R] 中有几个数的贡献区间能完整覆盖 [L, R] 区间。但是数据范围挺大的,可以考虑用树状数组离线处理来达到优化的目的。先对所有的查询进行排序 (按照L升序排列) ,然后从左到右依次处理。我们用树状数组区间和sum [L, R] 表示区间[L, R]中符合题意的有多少个数。假设现在需要查询 [L, R] 区间,我们可以考虑贡献区间L[i]<L的数,可以在i位置加 1,然后在R[i]位置减1。这样处理的话必须要保证L[i]小于查询区间L的值,以及i要在查询区间内。所以我们每次向后移动的时候,要在树状数组中减去当前位置的数对树状数组的影响,也就是进行操作 i 位置减1,R[i]位置加1. 分析到这里这个题目就变成了一个比较水的利用树状数组进行点更新,区间查询的题目了,也可以用线段树搞的。
1 #include <vector> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 200010; 9 struct node 10 { 11 int l, r, num; 12 }q[maxn]; 13 int tree[maxn], a[maxn], vis[maxn]; 14 int ans[maxn], L[maxn], R[maxn]; 15 16 vector <int> vec[maxn]; 17 vector <int> p[maxn]; 18 bool cmp (node a, node b) 19 { 20 return a.l < b.l; 21 } 22 //预处理每个数的因子 23 void init () 24 { 25 for (int i=0; i<maxn; i++) 26 p[i].clear(); 27 for (int i=2; i<maxn; i++) 28 for (int j=i; j<maxn; j+=i) 29 p[j].push_back(i); 30 } 31 //树状数组 32 int lowbit (int x) 33 { 34 return x & (-x); 35 } 36 void add (int x, int val) 37 { 38 for (int i=x; i<maxn; i+=lowbit(i)) 39 tree[i] += val; 40 } 41 int Sum (int x) 42 { 43 int sum = 0; 44 while (x) 45 { 46 sum += tree[x]; 47 x -= lowbit(x); 48 } 49 return sum; 50 } 51 52 int main () 53 { 54 int n, Q; 55 init (); 56 while (scanf ("%d %d", &n, &Q), n + Q) 57 { 58 for (int i=1; i<=n; i++) 59 scanf ("%d", &a[i]); 60 for (int i=0; i<Q; i++) 61 { 62 scanf ("%d %d", &q[i].l, &q[i].r); 63 q[i].num = i; 64 } 65 66 sort (q, q+Q, cmp); 67 memset (vis, 0, sizeof(vis)); 68 //预处理每个数的左边界 69 for (int i=1; i<=n; i++) 70 { 71 L[i] = 0; 72 for (int j=0; j<p[a[i]].size(); j++) 73 { 74 int x = p[a[i]][j]; 75 L[i] = max (L[i], vis[x]); 76 vis[x] = i; 77 } 78 } 79 //预处理每个数的右边界 80 for (int i=0; i<=maxn; i++) 81 { 82 vec[i].clear(); 83 vis[i] = n + 1; 84 } 85 for (int i=n; i>0; i--) 86 { 87 R[i] = n + 1; 88 for (int j=0; j<p[a[i]].size(); j++) 89 { 90 int x = p[a[i]][j]; 91 R[i] = min (R[i], vis[x]); 92 vis[x] = i; 93 } 94 } 95 96 memset (tree, 0, sizeof(tree)); 97 for (int i=1; i<=n; i++) 98 { 99 if (L[i]) 100 vec[L[i]].push_back(i); 101 else 102 { 103 add (i, 1); 104 if (R[i] <= n) 105 add (R[i], -1); 106 } 107 } 108 for (int i=1, j=0; i<=n; i++) 109 { 110 while (q[j].l == i && j < Q) 111 { 112 ans[q[j].num] = Sum(q[j].r) - Sum(q[j].l-1); 113 j ++; 114 } 115 add (i, -1); 116 if (R[i] <= n) 117 add (R[i], 1); 118 for (int k=0; k<vec[i].size(); k++) 119 { 120 int x = vec[i][k]; 121 add (x, 1); 122 add (R[x], -1); 123 } 124 } 125 for (int i=0; i<Q; i++) 126 printf ("%d\n", ans[i]); 127 } 128 return 0; 129 }
本文为博主原创文章,未经博主允许不得转载。