CF914D Bash and a Tough Math Puzzle (线段树二分)
Description
给定一个序列 a a a,有 q q q 个询问,两个操作。
1 l r x猜测区间 [ l , r ] [l, r] [l, r] 中的 g c d gcd gcd 是 x x x。你需要判断他的这个猜测是否是几乎正确的,几乎正确为:暂时修改任意一个数或不修改的情况下是正确的。2 i y将 a i a_i ai 改成 y y y。
1 ≤ n ≤ 5 × 1 0 5 , 1 ≤ q ≤ 4 × 1 0 5 , 1 ≤ a i ≤ 1 0 9 1 \leq n \leq 5 \times 10^5, 1 \leq q \leq 4 \times 10^5, 1 \leq a_i \leq 10^9 1≤n≤5×105,1≤q≤4×105,1≤ai≤109。
Solution
因为只能修改一个数,所以在线段树上二分找不是
x
x
x 倍数的数为
c
n
t
cnt
cnt。如
c
n
t
>
1
cnt > 1
cnt>1 为 NO,否则为 YES。方案为:
c
n
t
=
1
cnt=1
cnt=1 时将那个数变成
x
x
x,
c
n
t
=
0
cnt = 0
cnt=0 随便选一个数变成
x
x
x。
Code
#include <bits/stdc++.h>
const int N = 2e6 + 5;
#define lson p << 1
#define rson (p << 1) | 1
int a[N], cnt;
struct node{
int l, r, val;
}tree[N];
int gcd(int a, int b){
return b == 0 ? a : gcd(b, a % b);
}
void build(int p, int l, int r) {
tree[p].l = l, tree[p].r = r;
if (l == r){
tree[p].val = a[l];
return ;
}
int mid = (l + r) >> 1;
build(lson, l, mid); build(rson, mid + 1, r);
tree[p].val = gcd(tree[lson].val, tree[rson].val);
}
void update(int p, int x, int k) {
if (tree[p].l == tree[p].r) {
tree[p].val = k;
return ;
}
int mid = (tree[p].l + tree[p].r) >> 1;
if (x <= mid) update(lson, x, k);
else update(rson, x, k);
tree[p].val = gcd(tree[lson].val, tree[rson].val);
}
void query(int p, int l, int r, int k) {
if (cnt > 1) return ;
if (tree[p].l == tree[p].r) {
if (tree[p].val % k) cnt++;
return ;
}
int mid = (tree[p].l + tree[p].r) >> 1;
if (l <= mid && tree[lson].val % k) query(lson, l, r, k);
if (r > mid && tree[rson].val % k) query(rson, l, r, k);
}
int main(){
int n, m; scanf("%d", &n);
for (int i = 1; i <= n ;i++) scanf("%d", &a[i]);
build(1, 1, n);
scanf("%d", &m);
while(m--) {
int opt, l, r, k;
scanf("%d%d%d", &opt, &l, &r);
cnt = 0;
if (opt == 1) {
scanf("%d", &k),
query(1, l, r, k);
if (cnt <= 1) puts("YES");
else puts("NO");
}
else update(1, l, r);
}
return 0;
}

浙公网安备 33010602011771号