P1890 gcd区间 线段树

Posted paranoid-ls

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1890 gcd区间 线段树相关的知识,希望对你有一定的参考价值。

题目描述

给定一行\(n\)个正整数\(a[1]..a[n]\)

\(m\)次询问,每次询问给定一个区间\([L,R]\),输出\(a[L]..a[R]\)的最大公因数。

输入格式

第一行两个整数\(n,m\)

第二行n个整数表示\(a[1]..a[n]\)

以下\(m\)行,每行\(2\)个整数表示询问区间的左右端点。

保证输入数据合法。

输出格式

共m行,每行表示一个询问的答案。

输入输出样例

输入 #1

5 3
4 12 3 6 7
1 3
2 3
5 5

输出 #1

1
3
7

说明/提示

对于30%的数据,\(n <= 100, m <= 10\)

对于60%的数据,\(m <= 1000\)

对于100%的数据,\(1 <= n <= 1000,1 <= m <= 1,000,000\)

 0 < 数字大小 <= 1,000,000,000

题解:

这里提供一种结构体指针线段树的写法:

做这道题,你首先要知道\(gcd\)的求法,由欧几里得算法可知:

int gcd(int x, int y)  return y == 0 ? x : gcd(y, x % y); 

其次,\(gcd\)满足区间可加性,即:
\[ gcd(l, r) = gcd(gcd(l, k), gcd(k+1, r)),k\in[l, r] \]
线段树直接维护即可...

code:

#include <iostream>
#include <cstdio>
using namespace std;
int read() 
    int x = 0, f = 1; char ch;
    while(! isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(x = ch^48; isdigit(ch = getchar()); x = (x<<3) + (x<<1) + (ch^48));
    return x * f;

int n, m;
inline int gcdd(int x, int y)  return y == 0 ? x : gcdd(y, x % y); 
struct Segment 
    struct node 
        int l, r, gc;
        node* ch[2];
        node(int l, int r, int gc) : l(l), r(r), gc(gc) 
        inline int mid()  return (l + r) >> 1; 
        inline void up()  gc = gcdd(ch[0]->gc, ch[1]->gc); 
     *root;
    void build(node *&o, int l, int r) 
        o = new node (l, r, 0);
        if(l == r)  o->gc = read(); return; 
        build(o->ch[0], l, o->mid());
        build(o->ch[1], o->mid()+1, r);
        o->up();
    
    int query(node *o, int l, int r) 
        if(l <= o->l && o->r <= r) return o->gc;
        int res = 0;
        if(o->mid() >= l) res = query(o->ch[0], l, r);
        if(o->mid() < r) res = gcdd(res, query(o->ch[1], l, r));
        return res;
    
 tr;
int main() 
    n = read(); m = read();
    tr.build(tr.root, 1, n);
    for(int i = 1, l, r; i <= m; ++ i) 
        l = read(); r =  read();
        printf("%d\n", tr.query(tr.root, l, r));
    
    return 0;

以上是关于P1890 gcd区间 线段树的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 914D - Bash and a Tough Math Puzzle 线段树,区间GCD

[线段树 差分 区间转单点]区间最大公约数

codeforces CF474F Ant colony 线段树 区间gcd

Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论

hdu 5381 The sum of gcd(线段树+gcd)

HDU - 5381 The sum of gcd(莫队/线段树区间合并)