【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;
}

浙公网安备 33010602011771号