[Easy] QOJ9543 Good Partitions
2025/6/7约 578 字大约 3 分钟
简要题意
给定一个长度为 的序列 。
定义一个数 是好的,当且仅当 。
有 次操作,每次操作给出 ,将 变为 。在所有操作前以及每次操作后,输出 中好的数的数量。
组数据。。
思路
考虑好的数有什么性质。对于 ,那么 必须分到题意中不同的段中,换句话说 必须是好的数的倍数。换句话说如果能够求出所有形如 的 的 gcd,那么答案就是这个 gcd 的因子个数。
于是我们需要一个数据结构,支持插入一个数,删除一个数,查询所有数的 gcd。由于插入删除 可以看成在 处单点修改,而 又满足结合律,因此可以用线段树维护。时间复杂度 。
代码
#include <bits/stdc++.h>
#define ls (i << 1)
#define rs (i << 1 | 1)
#define mid ((l + r) >> 1)
using namespace std;
const int N = 2e5 + 5;
template<int N>
struct sgt {
int t[N << 2];
void update(int p, int v, int i, int l, int r){
if(l > r) return;
if(l == r) return t[i] = v, void();
if(p <= mid) update(p, v, ls, l, mid);
else update(p, v, rs, mid + 1, r);
t[i] = __gcd(t[ls], t[rs]);
}
void build(function<int(int)> f, int i, int l, int r){
if(l > r) return;
if(l == r) return t[i] = f(l), void();
build(f, ls, l, mid), build(f, rs, mid + 1, r);
t[i] = __gcd(t[ls], t[rs]);
}
};
sgt<N> t;
int n, q, a[N], d[N];
void solve(){
cin >> n >> q;
for(int i=1;i<=n;i++) cin >> a[i];
d[0] = n;
t.build([](int i){
return a[i] > a[i + 1] ? i : 0;
}, 1, 1, n - 1);
cout << d[t.t[1]] << '\n';
while(q--){
int p, v; cin >> p >> v;
a[p] = v;
if(p < n) t.update(p, a[p] > a[p + 1] ? p : 0, 1, 1, n - 1);
if(p > 1) t.update(p - 1, a[p - 1] > a[p] ? p - 1 : 0, 1, 1, n - 1);
cout << d[t.t[1]] << '\n';
}
}
void init(int n){
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j+=i) d[j]++;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t, init(2e5);
while(t--) solve();
return 0;
}
// Written by xiezheyuan