题目大意:
给你一个序列,你要在这个序列上进行
m
m
m次操作,操作
1
:
l
,
r
,
x
1:l,r,x
1:l,r,x表示判断是否序列区间
[
l
,
r
]
[l,r]
[l,r]中所有数的
g
c
d
(
)
=
x
gcd()=x
gcd()=x,如果不等于你可以修改其中一个数的值。操作
2
:
i
,
y
将
a
i
=
y
2:i,y将ai= y
2:i,y将ai=y。
思路:
注意到
q
=
4
e
5
q=4e5
q=4e5也就是说你的所有操作要在
O
(
l
o
g
n
)
O(logn)
O(logn)内完成才能通过这题,所以我们考虑采用线段树来解决这题。操作二比较简单就是基础的单点修改,我们来考虑一下操作一,当
g
c
d
(
l
,
r
)
gcd(l,r)
gcd(l,r) mod
x
=
0
x = 0
x=0也就是说这个区间内所有的数都是
x
x
x的倍数,那么我们随便修改其中一个数为
x
x
x,就会有整体的
g
c
d
=
x
gcd=x
gcd=x.当一个区间
g
c
d
(
l
i
,
r
i
)
gcd(li,ri)
gcd(li,ri) mod
x
!
=
0
x!=0
x!=0,也就是说这个区间至少有一个数不是
x
x
x的倍数。但是我们无法确定是哪个数,所有我们需要递归要叶子节点才能确定,如果到达叶子节点并且这个节点 mod
x
!
=
0
x!=0
x!=0,说明要想使得
g
c
d
(
l
,
r
)
=
x
gcd(l,r)=x
gcd(l,r)=x那么这个数必须要修改,我们用
c
n
t
cnt
cnt来统计需要修改的节点个数。如果当前区间左右儿子都不是
x
x
x的倍数必要要修改两个数,我们直接剪枝令
c
n
t
=
2
,
r
e
t
u
r
n
cnt=2,return
cnt=2,return。最后根据
c
n
t
cnt
cnt来输出就行了。
总结:线段树维护区间
g
c
d
gcd
gcd。利用
g
c
d
gcd
gcd性质剪枝以及思考,总体不是很难。还有需要注意的就是当一个区间
g
c
d
[
l
i
,
r
i
]
gcd[li,ri]
gcd[li,ri] mod
x
!
=
0
x!=0
x!=0,需要一直递归到叶子节点才能判断,不能直接
c
n
t
+
+
cnt++
cnt++,因为可能在某一个子区间有左右儿子 mod
x
x
x都不等于0。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
typedef long long int ll;
struct seg{
int l,r;
int gcd;
seg(){}
seg(int a,int b):l(a),r(b){}
}tree[maxn << 2];
void build(int id,int l,int r){
tree[id] = {l,r};
if(l == r){
scanf("%d",&tree[id].gcd);
return ;
}
int mid = l + r >> 1;
build(id << 1,l,mid);
build((id << 1) + 1,mid + 1, r);
tree[id].gcd = __gcd(tree[id << 1].gcd,tree[(id << 1) + 1].gcd);
}
void update(int id,int a,int b){
if(tree[id].l == tree[id].r && tree[id].l == a){
tree[id].gcd = b;
return ;
}
int mid = tree[id].l + tree[id].r >> 1;
if(a <= mid)update(id << 1,a,b);
else update((id << 1) + 1,a,b);
tree[id].gcd = __gcd(tree[id << 1].gcd,tree[(id << 1) + 1].gcd);
}
void query(int id,int l,int r,int x,int &cnt){
if(cnt >= 2){return;}
if(tree[id].l >= l && tree[id].r <= r){
if(tree[id].gcd % x == 0)return ;
else if(tree[id].l == tree[id].r){cnt++;return;}
if(tree[id << 1].gcd % x != 0 && tree[(id << 1) + 1].gcd % x != 0){
cnt = 2;return;
}
if(tree[id << 1].gcd % x != 0)
query(id << 1,l,r,x,cnt);
if(tree[(id << 1) + 1].gcd % x != 0)
query((id << 1) + 1,l,r,x,cnt);
return;
}
int mid = tree[id].l + tree[id].r >> 1;
if(r <= mid) query(id << 1,l,r,x,cnt);
else if(l > mid) query((id << 1) + 1,l,r,x,cnt);
else query(id << 1,l,r,x,cnt) , query((id << 1) + 1,l,r,x,cnt);
}
void solved(){
int n;scanf("%d",&n);
build(1,1,n);
int q;scanf("%d",&q);
int l,r,x;
while(q--){
int ins;scanf("%d",&ins);
if(ins == 1){
int cnt = 0;
scanf("%d%d%d",&l,&r,&x);
if(l == r){cout<<"YES"<<endl;continue;}
query(1,l,r,x,cnt);
if(cnt <= 1)printf("YES\n");
else printf("NO\n");
}
if(ins == 2){
ll i,y;
scanf("%lld%lld",&i,&y);
update(1,i,y);
}
}
}
int main(){
solved();
return 0;
}