【09.07】CCPC网络赛08题 GCD on Sequence (吉司机线段树)

传送门

题解

从大到小枚举gcd值,维护每个左端点为区间起始点,至少需要延伸的位置。每次gcd值变小后,某一左端点起始到达的位置将会变小,可以用吉司机线段树,维护区间和,并对区间取min操作。

代码

/*************************************************************************
    > File Name: 1.cpp
    > Author: Knowledge-Pig
    > Mail: 925538513@qq.com
    > Blog: https://www.cnblogs.com/Knowledge-Pig/
    > Created Time: 2021年09月02日 星期四 10时49分39秒
************************************************************************/

#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define LL long long
#define pb push_back
#define fi first
#define se second
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
#define endl '\n'
#define ls (node << 1)
#define rs (node << 1 | 1)
using namespace std;
const int maxx = 2e5 + 10;
int n, a[maxx];
LL sum[maxx << 1], mx[maxx << 1], se[maxx << 1],  cnt[maxx << 1], ans[maxx];
void push_up(int node){
    sum[node] = sum[ls] + sum[rs];
    mx[node] = max(mx[ls], mx[rs]);
    se[node] = max(se[ls], se[rs]);
    cnt[node] = 0;
    if(mx[node] == mx[ls]) cnt[node] += cnt[ls];
    else se[node] = max(se[node], mx[ls]);
    if(mx[node] == mx[rs]) cnt[node] += cnt[rs];
    else se[node] = max(se[node], mx[rs]);
}
void build(int node, int l, int r){
    if(l == r){
        sum[node] = mx[node] = n + 1;
        se[node] = -1; cnt[node] = 1;
        return;
    }
    int mid = l + r >> 1;
    build(ls, l, mid); build(rs, mid + 1, r);
    push_up(node);
}
void calc(int node, int val){
    if(val >= mx[node]) return;
    sum[node] -= cnt[node] * (mx[node] - val);
    mx[node] = val;
}

void push_down(int node){
    calc(ls, mx[node]);
    calc(rs, mx[node]);
}

void update(int node, int l, int r, int ql, int qr, int val){
    if(val >= mx[node]) return;
    if(ql <= l && qr >= r && val > se[node]){
        calc(node, val);
        return;
    }
    push_down(node);
    int mid = l + r >> 1;
    if(qr <= mid) update(ls, l, mid, ql, qr, val);
    else if(ql > mid) update(rs, mid + 1, r, ql, qr, val);
    else{
        update(ls, l, mid, ql, mid, val);
        update(rs, mid + 1, r, mid + 1, qr, val);
    }
    push_up(node);
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0);
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
    freopen("output.out", "w", stdout);
#endif
    int T;
    cin >> T;
    while(T--){
        cin >> n;
        for(int i = 1, u; i <= n; ++i){ cin >> u; a[u] = i; }
        build(1, 1, n);
        for(int i = n / 2; i >= 1; --i){
            vector<int> vec;
            for(int j = i; j <= n; j += i) vec.pb(a[j]);
            sort(vec.begin(), vec.end());
            for(int j = 0, l = 0; j < vec.size() - 1; ++j){
                update(1, 1, n, l + 1, vec[j], vec[j + 1]);
                l = vec[j];
            }
            ans[i] = (n + 1ll) * n - sum[1];
        }
        for(int i = 1; i <= n; ++i){ cout << ans[i] - ans[i + 1] << endl; ans[i] = 0; }
        ans[n + 1] = 0;
    }
    return 0;
}
posted @ 2021-09-07 10:55  Knowledge-Pig  阅读(18)  评论(0)    收藏  举报