题解:P12579 [UOI 2021] 哥萨克与 GCD
Little_corn · · 题解
来个简单做法。
首先考虑如何判定一组询问是合法的,令
根据
考虑优化,不难发现前缀
::::info[代码]
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pir pair<ll, ll>
#define mkpir make_pair
#define umap unordered_map
#define pb emplace_back
#define fi first
#define se second
#define db double
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
const ll INF = 1e18, mod = 998244353;
const db eps = 1e-9;
/*
struct edge{
int v, next;
}edges[M << 1];
int head[N], idx;
il void add_edge(int u, int v){
edges[++idx] = {v, head[u]};
head[u] = idx;
}
*/
il void chkmax(ll& x, ll y){if(x < y) x = y;}
il void chkmin(ll& x, ll y){if(x > y) x = y;}
il void chkmax(int& x, int y){if(x < y) x = y;}
il void chkmin(int& x, int y){if(x > y) x = y;}
il void ADD(ll& x, ll y){x += y; ((x >= mod) ? x -= mod : 0ll);}
il void MUL(ll& x, ll y){x = x * y % mod;}
il ll qpow(ll x, int y){
ll ret = 1;
for(; y; y >>= 1, MUL(x, x)) if(y & 1) MUL(ret, x);
return ret;
}
//#define int long long
int n, a[N], pre[N], suf[N];
struct Segtree{
#define ls (o << 1)
#define rs (o << 1 | 1)
#define mid ((l + r) >> 1)
int gd[N << 2];
void pushup(int o){gd[o] = __gcd(gd[ls], gd[rs]);}
void build(int o, int l, int r){
if(l == r) return gd[o] = a[l], void();
build(ls, l, mid); build(rs, mid + 1, r);
pushup(o);
}
void modify(int o, int l, int r, int x, int v){
if(l == r) return gd[o] = v, void();
if(x <= mid) modify(ls, l, mid, x, v);
else modify(rs, mid + 1, r, x, v);
pushup(o);
}
int getval(int o, int l, int r, int s, int t){
if(l == 0 || r == n + 1) return 0;
if(s <= l && r <= t) return gd[o];
int ret = 0;
if(s <= mid) ret = __gcd(ret, getval(ls, l, mid, s, t));
if(mid < t) ret = __gcd(ret, getval(rs, mid + 1, r, s, t));
return ret;
}
int getL(int o, int l, int r, int v, int pi){
if(__gcd(v, gd[o]) >= pi) return r + 1;
if(l == r) return l; int L = __gcd(v, gd[ls]);
if(L < pi) return getL(ls, l, mid, v, pi);
else return getL(rs, mid + 1, r, L, pi);
}
int getR(int o, int l, int r, int v, int pi){
if(__gcd(v, gd[o]) >= pi) return l - 1;
if(l == r) return l; int R = __gcd(v, gd[rs]);
if(R < pi) return getR(rs, mid + 1, r, v, pi);
else return getR(ls, l, mid, R, pi);
}
}tr;
void bf(){
for(int i = 1; i <= n; i++) pre[i] = __gcd(pre[i - 1], a[i]);
for(int i = n; i; i--) suf[i] = __gcd(suf[i + 1], a[i]);
ll ans = pre[n];
for(int i = 1; i < n; i++) ans += min(suf[i + 1], pre[i]);
cout << ans << "\n";
}
struct Seg{
int l, r, v;
}sl[N], sr[N];
void solve(){
int l = 1, now = a[1], lt = 0, r, rt = 0;
while(l <= n){
r = tr.getL(1, 1, n, 0, now);
sl[++lt] = (Seg){l, r - 1, now}; now = tr.getval(1, 1, n, 1, r);
l = r;
} now = a[n], r = n;
while(r > 0){
l = tr.getR(1, 1, n, 0, now);
sr[++rt] = (Seg){l, r - 1, now}; now = tr.getval(1, 1, n, l, n);
r = l;
} ll ans = tr.getval(1, 1, n, 1, n);
for(int i = 1; i <= lt; i++) for(int j = 1; j <= rt; j++){
int L = max(sl[i].l, sr[j].l), R = min(sl[i].r, sr[j].r);
if(L > R) continue;
ans += 1ll * (R - L + 1) * min(sl[i].v, sr[j].v);
} cout << ans << "\n";
}
signed main(){
//freopen(".in", "r", stdin);
//freopen(".out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int Q; cin >> n >> Q;
for(int i = 1; i <= n; i++) cin >> a[i];
tr.build(1, 1, n); solve();
while(Q--){
int x, y; cin >> x >> y;
a[x] = y; tr.modify(1, 1, n, x, y); solve();
}
return 0;
}