st表,线段树,gcd的想法

原文:大佬博客:https://www.cnblogs.com/Emcikem/p/13764618.html

get到的一些东西,gcd是log级别的,也就是说,随着gcd(a, b, c, d…)的增多,gcd的值不会增多的,只会是log级别的,因为一个就是log级别的,多个只能比log级别小。。。,所以可以区间分割,分割成相同的gcd的区间。

Be Geeks! - 子区间gcd和,线段树 + 单调栈 + ST表求区间gcd + 二分
        </h1>
        <div class="clear"></div>
        <div class="postBody">
            <div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown">

传送门
ni=1nj=imax(ai,...,aj)gcd(ai,...,aj)∑i=1n∑j=inmax(ai,...,aj)∗gcd(ai,...,aj)所在的区间,然后进行区间加 + 区间和查询即可。
每次找到新的gcd就把这段gcd乘以这段区间的最值累积加起来即可。

ST表的常数优化真香

#include <iostream>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
const int N = 2e5 + 5;
const int mod = 1e9 + 7;
struct SegTree{
    
    
    struct Tree{
    
    
        int l, r, val;
        int lazy;
        #define l(p) tree[p].l
        #define r(p) tree[p].r
        #define val(p) tree[p].val
        #define lazy(p) tree[p].lazy
        #define lson p << 1
        #define rson p << 1 | 1
    } tree[N << 2];
    void pushup(int p){
        val(p) = (val(lson) + val(rson)) % mod;
    }
    void pushdown(int p){
        if(lazy(p)) {
            lazy(lson) = lazy(p);
            lazy(rson) = lazy(p);
            val(lson) = 1ll * lazy(p) * (r(lson) - l(lson) + 1) % mod;
            val(rson) = 1ll * lazy(p) * (r(rson) - l(rson) + 1) % mod; 
            lazy(p) = 0;
        }
    }
    void build(int p, int l, int r){
        l(p) = l, r(p) = r; lazy(p) = val(p) = 0;
        if(l == r) {
            return ;
        }
        int mid = (l + r) >> 1;
        build(lson, l, mid);
        build(rson, mid + 1, r);
        pushup(p);
    }
    void change(int p, int l, int r, int x){
        if(l <= l(p) && r(p) <= r) {
            val(p) = 1ll * x * (r(p) - l(p) + 1) % mod;
            lazy(p) = x;
            return;
        }
        pushdown(p);
        int mid = (l(p) + r(p)) >> 1;
        if(l <= mid) change(lson, l, r, x);
        if(r > mid) change(rson, l, r, x);
        pushup(p);
    }
    int query(int p, int l, int r){
        if(l <= l(p) && r(p) <= r) {
            return val(p);
        }
        pushdown(p);
        int mid = (l(p) + r(p)) >> 1;
        int ans = 0;
        if(l <= mid) ans = (ans + query(lson, l, r)) % mod;
        if(r > mid) ans = (ans + query(rson, l, r)) % mod;
        return ans; 
    }
} seg; // 区间加法 + 区间和查询

int lans[N], lg[N], stk[N], a[N], top, n;
int st[N][20];
int gcd(int a, int b){
return b == 0 ? a : gcd(b, a % b);
}
void init(){
top = 0;
lg[1] = 0;
for(int i = 2;i <= n; i++) lg[i] = lg[i >> 1] + 1;
for(int i = 1; i <= n; i++) {
while(top && a[stk[top]] < a[i]) top–;
lans[i] = (!top ? 0 : stk[top]) + 1;
stk[++top] = i;
}
for(int i = 1; i <= n; i++) st[i][0] = a[i];
int k = log2(n / 2) + 1;
for(int j = 1; j <= k; j++)
for(int i = 1; i + (1 << j) - 1 <= n; i++)
st[i][j] = gcd(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
int query(int l, int r){ //ST表区间查询gcd
int k = lg[r - l + 1];
return gcd(st[l][k], st[r - (1 << k) + 1][k]);
}
ll ans = 0;
void work(int x, int ups){ // 分段求gcd 再乘以系数
if(x <= 0)return;
int l = 1, r = x, stdd = query(x, ups);
while(l < r){
int mid = (l + r) >> 1;
if(query(mid, ups) == stdd) r = mid;
else l = mid + 1;
}
ans = (ans + 1ll * seg.query(1, l, x) * stdd) % mod;
work(l - 1, ups);
}
namespace IO {
template <typename T>
inline void w(T x) { if (x > 9) w(x / 10); putchar(x % 10 + 48); }
template <typename T>
inline void write(T x, char c) { if(x < 0) putchar(’-’), x = -x;w(x); putchar©; }
template <typename T>
inline void read(T &x) {
x = 0; T f = 1; char c = getchar();
for (; !isdigit©; c = getchar()) if (c == ‘-’) f = -1;
for (; isdigit©; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
x *= f;
}
};
int main(){
IO::read(n);
seg.build(1, 1, n);
for(int i = 1; i <= n; i++) IO::read(a[i]);
init();
for(int i = 1; i <= n; i++) {
seg.change(1, lans[i], i, a[i]); // 每次更新以i为最大值的区间,加上a[i];
work(i, i);
}
IO::write(ans, ‘\n’);
return 0;
}

I‘m Stein, welcome to my blog
<div id="blog_post_info">
1
0
<div class="clear"></div>
<div id="post_next_prev">

<a href="https://www.cnblogs.com/Emcikem/p/13764163.html" class="p_n_p_prefix" one-link-mark="yes">« </a> 上一篇:    <a href="https://www.cnblogs.com/Emcikem/p/13764163.html" title="发布于 2020-10-03 14:27" one-link-mark="yes">P6327 区间加区间sin和 - 三角函数和差公式 + 线段树</a>
<br>
<a href="https://www.cnblogs.com/Emcikem/p/13802503.html" class="p_n_p_prefix" one-link-mark="yes">» </a> 下一篇:    <a href="https://www.cnblogs.com/Emcikem/p/13802503.html" title="发布于 2020-10-12 14:03" one-link-mark="yes">HDU - 2157  - 邻接矩阵k条路定理 - 矩阵快速幂</a>
posted @ 2020-10-03 16:42  Emcikem  阅读( 118)  评论( 0编辑  收藏

おすすめ

転載: blog.csdn.net/YingShen_xyz/article/details/117171736