题目链接:Problem - 914D - Codeforces
题目大意:给你长度为n的数组, 然后q次查询,有两种选择
1 l r x ( 1 ≤ l ≤ r ≤ n , 1 ≤ x ≤ 109 ).
2 i y . (1 ≤ i ≤ n , 1 ≤ y ≤ 109) .
第一种判断 区间[l, r] 是否满足猜测, 在[l ,r] 区间最多 可以修改一个值 (可以不改),让区间的gcd == x
第二种将位置 i 上的数改为 y
输入:第一行包含一个整数 n ( 1 ≤ n ≤ 5·1e5 );- 数组的大小。( 1 ≤ n ≤ 5·1e5 ) - 数组的大小。
第二行包含 n 个整数 a 1, a 2, ..., a n ( 1 ≤ a i ≤ 1e9 - 数组的元素。
第三行包含一个整数 q ( 1 ≤ q ≤ 4·1e5 ) - 查询次数。
接下来的 q 行对查询进行了描述,可能有以下几种形式:
- 1 l r x ( 1 ≤ l ≤ r ≤ n , 1 ≤ x ≤ 1e9 ).
- 2 i y . (1 ≤ i ≤ n , 1 ≤ y ≤ 1e9) .
保证至少有一个第一种类型的查询。
输出:满足 YES, 否则 NO
算法: 线段树, 数论
-
首先手玩一组样例 12 8 18 24 , 此时 假设查询 x = 4, 明显可以的。 x=2, 也是可以的, 只需要将其中的任意一个数改为2即可。x = 3 or 6, 也是可以的 将8 改为3 即可。 但如果是x=12,就不行了 就要修改两个数字 8 18 才可以了 。
-
结论:要想满足基本gcd的猜想,
-
就要让[l, r]区间(总数:r-l+1)里的 r - l 个数, 都可以整除x。
-
或本来 r-l+1个数就可以整除 x , 也是可以的(修改一个数为x即可)。
3.两者都只需要改一个数即可, 其他的情况都是NO
- 做法: 采用线段树维护 gcd, 加单点修改。 进行查询时, 判断左子树是否可以整除x, 以及右子树是否可以整除x, 不能整除, 向下查询, 当到达叶子节点时,说明该数据需要修改,然后统计一下。 注意 当tot > 1 直接return, 防止卡时间。
cpp
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
using ui64 = unsigned long long;
const int N = 5e5+2;
int a[N];
struct Node{
int l, r;
int g;
Node(){
this->l = this->r = 0;
this->g = 0;
}
}tr[N<<2];
void up(int id){// 线段树维护gcd
tr[id].g = gcd(tr[id<<1].g, tr[id<<1|1].g);
}
void build(int id, int l, int r ){
tr[id].l = l;
tr[id].r = r;
if(l==r) {
tr[id].g = a[r];
return;
}
int mid = (l+r)>>1;
build(id<<1, l, mid);
build(id<<1|1, mid+1, r);
up(id);
}
void updata(int id, int jobt, int jobv){// 单点修改
if(tr[id].l == tr[id].r) {
tr[id].g = jobv;
return;
}
int mid = (tr[id].l + tr[id].r) >> 1;
if(jobt <= mid) {
updata(id<<1, jobt, jobv);
}else{
updata(id<<1|1, jobt, jobv);
}
up(id);
}
int tot;
void query(int id, int jobl, int jobr, int jobv){
if(tr[id].l == tr[id].r) {
tot++;
return;
}
if(tot>1)return;
int mid = (tr[id].l + tr[id].r) >> 1;
if(jobl <= mid && tr[id<<1].g % jobv != 0) {//左子树
query(id<<1, jobl, jobr, jobv);
}
if(jobr > mid && tr[id<<1|1].g % jobv != 0) {//右子树
query(id<<1|1, jobl, jobr,jobv);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n;
cin >> n;
for(int i=1; i<=n; i++) {
cin >> a[i];
}
build(1, 1, n);
int quy;
cin >> quy;
while(quy--) {
int op;
cin >> op;
if(op == 1) {
tot = 0; // 归0
int jobl, jobr, jobx;
cin >> jobl >> jobr >> jobx;
query(1, jobl, jobr,jobx);
if(tot<=1){
cout << "YES\n";
}else{
cout << "NO\n";
}
}else{
int jobt, jobv;
cin >> jobt >> jobv;
updata(1, jobt, jobv);
}
}
return 0;
}
感谢收看与点赞, 欢迎大佬指正。