hdu 5317 RGCDQ 筛法+线段树解法

RGCDQ

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 299    Accepted Submission(s): 151

Problem Description

Mr. Hdu is interested in Greatest Common Divisor (GCD). He wants to find more and more interesting things about GCD. Today He comes up with Range Greatest Common Divisor Query (RGCDQ). What’s RGCDQ? Please let me explain it to you gradually. For a positive integer x, F(x) indicates the number of kind of prime factor of x. For example F(2)=1. F(10)=2, because 10=2*5. F(12)=2, because 12=2*2*3, there are two kinds of prime factor. For each query, we will get an interval [L, R], Hdu wants to know maxGCD(F(i),F(j)) (L≤i<j≤R)

Input

There are multiple queries. In the first line of the input file there is an integer T indicates the number of queries.
In the next T lines, each line contains L, R which is mentioned above.

All input items are integers.
1<= T <= 1000000
2<=L < R<=1000000

Output

For each query,output the answer in a single line. 
See the sample for more details.

Sample Input

2 2 3 3 5

Sample Output

1 1

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5317

题目大意:F(i)表示i的素因子数,求一个区间的[L,R]中,任取两个数的GCD(F[i],F[j])最大值。

思路:比较简单,先筛法打表,将F[i]的值求出,因为八个最小素数相乘即可达到上限,所以F[i]的值很小,再求出每个F[i]的所有因数。之后就是维护一下RMQ就行了。此题可以不用线段树,线段树的部分仅用于求RMQ。

AC代码:

1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <cmath>
  6 #include <algorithm>
  7 #include <vector>
  8 #include <queue>
  9 #include <set>
 10 #include <map>
 11 #include <stack>
 12 #include <limits.h>
 13 using namespace std;
 14 typedef long long LL;
 15 #define lson l, mid, rt << 1
 16 #define rson mid + 1, r, rt << 1 | 1
 17 #define y1 y234
 18 #define MAXN 1000010 // 1e6
 19 int t;
 20 bool vis[MAXN];
 21 int F[MAXN], ans[MAXN], last[MAXN];
 22 int tree[MAXN * 2 + 100000];
 23 struct node {
 24     int id, L, R;
 25     node(int L, int R, int id) :L(L), R(R), id(id) {}
 26     bool operator < (const node &w) const {
 27         return R < w.R;
 28     }
 29 };
 30 vector<node> Q;
 31 vector<int> Fyinshu[MAXN];
 32 void init() {
 33     vis[0] = vis[1] = true;
 34     for(int i = 2; i <= 1000000; i++) {
 35         if(!vis[i]) {
 36             F[i]++;
 37             for(int j = i + i; j <= 1000000; j += i) {
 38                 vis[j] = 1;
 39                 F[j]++;
 40             }
 41         }
 42     }
 43 }
 44 void Pushup(int rt) {
 45     tree[rt] = max(tree[rt << 1], tree[rt << 1 | 1]);
 46 }
 47 void Update(int num, int pos, int l, int r, int rt) {
 48     if(l == r) {
 49         tree[rt] = max(tree[rt], num);
 50         return;
 51     }
 52     int mid = (l + r) >> 1;
 53     if(pos <= mid) Update(num, pos, lson);
 54     else Update(num, pos, rson);
 55     Pushup(rt);
 56 }
 57 int Query(int st, int ed, int l, int r, int rt) {
 58     int res = 0;
 59     int mid = (l + r) >> 1;
 60     if(st <= l && r <= ed) {
 61         return tree[rt];
 62     }
 63     if(st <= mid) res = max(res, Query(st, ed, lson));
 64     if(ed > mid) res = max(res, Query(st, ed, rson));
 65     return res;
 66 }
 67 int main() {
 68     init();
 69     scanf("%d", &t);
 70     int st, ed, maxn = -1;
 71     for(int i = 1; i <= t; i++) {
 72         scanf("%d%d", &st, &ed);
 73         Q.push_back(node(st, ed, i));
 74         maxn = max(maxn, ed);
 75     }
 76     sort(Q.begin(), Q.end());
 77     for(int i = 1; i <= maxn; i++) {
 78         int tmp = F[i];
 79         Fyinshu[tmp].clear();
 80         for(int j = 1; j * j <= tmp; j++) {
 81             if(tmp % j != 0) continue;
 82             Fyinshu[tmp].push_back(j);
 83             if(j * j != tmp) Fyinshu[tmp].push_back(tmp / j);
 84         }
 85     }
 86     int q_cnt = 0;
 87     for(int i = 1; i <= maxn && q_cnt < t; i++) {
 88         int len = Fyinshu[F[i]].size();
 89         for(int j = 0; j < len; j++) {
 90             int tmp = Fyinshu[F[i]][j];
 91             if(last[tmp] != 0) {
 92                 Update(tmp, last[tmp], 1, maxn, 1);
 93             }
 94             last[tmp] = i;
 95         }
 96         for(; i == Q[q_cnt].R; q_cnt++) {
 97             if(Q[q_cnt].L == Q[q_cnt].R) ans[Q[q_cnt].id] = 0;
 98             ans[Q[q_cnt].id] = Query(Q[q_cnt].L, Q[q_cnt].R, 1, maxn, 1);
 99         }
100     }
101     for(int i = 1; i <= t; i++)
102         printf("%d\n", ans[i]);
103     return 0;
104 }

时间: 2024-10-15 04:50:58

hdu 5317 RGCDQ 筛法+线段树解法的相关文章

2015 HDU 多校联赛 5317 RGCDQ 筛法求解

2015 HDU 多校联赛 5317 RGCDQ 筛法求解 题目  http://acm.hdu.edu.cn/showproblem.php? pid=5317 本题的数据量非常大,測试样例多.数据量大, 所以必须做预处理.也就是用筛法求出全部的F[x],将全部F[x] 打印出来发现.事实上结果不大,最大的数值是7.所以对于每一个区间询问, 直接暴力求取有多少个 1 2 3 4 5 6 7 就可以,从大到小查找.假设出现2个以上 3-7 的数值,那么最大公约数就是该数字. 假设没有出现两个反复

HDU 1698 Just a Hook 线段树解法

很经典的题目,而且是标准的线段树增加lazy标志的入门题目. 做了好久线段树,果然是practice makes perfect, 这次很畅快,打完一次性AC了. 标志的线段树函数. 主要是: 更新的时候只更新到需要的节点,然后最后的时候一次性把所以节点都更新完毕. 这也是线段树常用的技术. #include <stdio.h> const int SIZE = 100005; struct Node { bool lazy; int metal; }; const int TREESIZE

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1

hdu 2795 Billboard(线段树)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10890    Accepted Submission(s): 4827 Problem Description At the entrance to the university, there is a huge rectangular billboard of

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

poj 3368 Frequent values(线段树解法)

题目链接:http://poj.org/problem?id=3368 题目大意:给你一段不下降的序列,求给定区间里出现次数最多的那个数字的次数. 思路:首先看到这题时,第一感觉线段树,但是仔细一看问题来啦,用线段数我怎么才能计算出某段区间里出现的那个数,因为出现最多的那个数可能不是在他它的左儿子上也不是在它的右儿子上,可能在当他们合并成一个区间时就出现啦,但是这儿我们需要注意的就是,题目给的是一段不下降的序列,那么突破口就出来啦,因为如果出现相同的数字,那么它们一定是连续的.所以我们只需要在普

HDU 3954 Level up 线段树

---NotOnlySuccess 出的题--- 看了题之后觉得和HDU 4027有点像,给的K很小,只有10,目测只要有人升级的时候直接更新到叶子节点就ok了.不过不同于HDU 4027 的是,那题每一次更新都相当于这题的一次升级操作,这题里面可能会出现一次操作之后没有升级和出现升级两种情况,一时半会没了思路. 无奈去搜题解,发现我只要维护一个区间当中距离升级最近的人所需要的基础升级经验,即不算等级加成的裸的升级经验,如果在一次涨经验之后,出现当前区间当中有人会升级,直接将每一个要升级的人更新

多校训练hdu --Nice boat(线段树,都是泪)

Nice boat Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 47 Accepted Submission(s): 10 Problem Description There is an old country and the king fell in love with a devil. The devil always ask

POJ 2828 Buy Tickets 线段树解法

此题应用线段树的方法非常巧妙.没做过真的难想得出是这么想的. 是一个逆向思维的运用. 其实一看到这道题目我就想到要运用逆向思维的了,但是就是没那么容易想通的. 思路: 1 要从后面往前更新线段树 2 线段树记录的是当前区间还剩下多少个记录空间 3 因为后面的插入会使得前面的插入往后退,那么前面插入的下标如果大于前面可以插入的空间,就需要往后退了. 好难理解的操作.仔细观察一下下面update这个函数吧. 二分地去查找适合的插入位置,把插入操作时间效率提高到 O(lgn),如果使用一般方法插入操作