题目大意
给定一个序列,支持两种操作:
- 单点修改
- 区间查询:是否存在一种方案,使得修改区间种0/1个元素后使得区间\(gcd = x\)。
\(n \leq 5 \times 10^5\)
思路
查询时,记query函数返回值为当前区间至少修改多少个元素使得区间gcd是x的倍数。
查询时,对于每个区间只需要找到一个不是x的倍数的数字即可。
复杂度\(O(nlogn)\)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n;
int a[N];
struct node {
int l,r;
int gcd;
}t[N << 2];
int gcd(int a,int b) {
return b == 0 ? a : gcd(b,a % b);
}
void update(int rt) {
int ch = rt << 1;
t[rt].gcd = gcd(t[ch].gcd,t[ch + 1].gcd);
}
void build(int l,int r,int rt) {
t[rt].l = l;
t[rt].r = r;
if(l == r) {
t[rt].gcd = a[l];
return;
}
int mid = (l + r) >> 1;
int ch = rt << 1;
build(l,mid,ch);
build(mid + 1,r,ch + 1);
update(rt);
}
void modify(int x,int rt,int v) {
if(t[rt].l == t[rt].r) {
t[rt].gcd = v;
return;
}
int mid = (t[rt].l + t[rt].r) >> 1;
int ch = rt << 1;
if(x <= mid) modify(x,ch,v);
else modify(x,ch + 1,v);
update(rt);
}
int query(int l,int r,int rt,int x) {
if(t[rt].gcd % x == 0) return 0;
if(l == t[rt].l and r == t[rt].r) {
if(l == r) return 1;
int ch = rt << 1;
if(t[ch].gcd % x == 0) {
return query(t[ch + 1].l,t[ch + 1].r,ch + 1,x);
}
if(t[ch + 1].gcd % x == 0) {
return query(t[ch].l,t[ch].r,ch,x);
}
return 2;
}
int ch = rt << 1;
int mid = (t[rt].l + t[rt].r) >> 1;
if(r <= mid) {
return query(l,r,ch,x);
}else if(l > mid) {
return query(l,r,ch + 1,x);
}else {
return query(l,mid,ch,x) + query(mid + 1,r,ch + 1,x);
}
}
int main () {
scanf("%d",&n);
for (int i = 1;i <= n; i ++) {
scanf("%d",&a[i]);
}
build(1,n,1);
int q;
cin >> q;
while(q --) {
int op;
scanf("%d",&op);
if(op == 1) {
int l,r,x;
scanf("%d %d %d",&l,&r,&x);
int ans = query(l,r,1,x);
if(ans <= 1) {
puts("YES");
}else puts("NO");
}
else {
int x,y;
scanf("%d %d",&x,&y);
modify(x,1,y);
}
}
return 0;
}