Description
Bash likes playing with arrays. He has an array a1 , a2 , … an of n integers. He likes to guess the greatest common divisor (gcd) of different segments of the array. Of course, sometimes the guess is not correct. However, Bash will be satisfied if his guess is almost correct.
Suppose he guesses that the gcd of the elements in the range [l, r] of a is x. He considers the guess to be almost correct if he can change at most one element in the segment such that the gcd of the segment is x after making the change. Note that when he guesses, he doesn’t actually change the array — he just wonders if the gcd of the segment can be made x. Apart from this, he also sometimes makes changes to the array itself.
Since he can’t figure it out himself, Bash wants you to tell him which of his guesses are almost correct. Formally, you have to process q queries of one of the following forms:
Note: The array is 1-indexed.
Input
The first line contains an integer n (1 ≤ n ≤ 5·10 5 ) — the size of the array.
The second line contains n integers a1 , a2 , …, an (1 ≤ ai ≤ 10 9 ) — the elements of the array.
The third line contains an integer q (1 ≤ q ≤ 4·10 5 ) — the number of queries.
The next q lines describe the queries and may have one of the following forms:
Guaranteed, that there is at least one query of first type.
Output
For each query of first type, output “YES” (without quotes) if Bash’s guess is almost correct and “NO” (without quotes) otherwise.
Examples
Input | Output |
---|---|
3 2 6 3 4 1 1 2 2 1 1 3 3 2 1 9 1 1 3 2 |
YES YES NO |
Input | Output |
---|---|
5 1 2 3 4 5 6 1 1 4 2 2 3 6 1 1 4 2 1 1 5 2 2 5 10 1 1 5 2 |
NO YES NO YES |
Note
In the first sample, the array initially is {2, 6, 3}.
For query 1, the first two numbers already have their gcd as 2.
For query 2, we can achieve a gcd of 3 by changing the first element of the array to 3. Note that the changes made during queries of type 1 are temporary and do not get reflected in the array.
After query 3, the array is now {9, 6, 3}.
For query 4, no matter which element you change, you cannot get the gcd of the range to be 2.
题意:n个数的数列,对它有下面两种操作
思路:
更新操作是比较简单的,只需要用log(n)找到这个数所在的叶子,修改它和所有与他相关的父亲即可。
询问操作的处理比较复杂,首先想到的是,为了检查x,需要求所询问区间的gcd,就要搜索所有相关的区间结点,求出gcd后再进一步操作。但是由于这个二叉树维护的是最大公因数,父节点维护的gcd一定可以整除子节点维护的gcd,可以利用这个性质来求解。
#include
#include
#define maxn 500000
#define fath(i) (i>>1)
#define left(i) (i<<1)
#define right(i) ((i<<1)+1)
#define mid(l,r) (l+ ((r -l) >> 1))
//完全二叉树用数组存放
int l[(maxn << 3) + 5] = { 0 };
int r[(maxn << 3) + 5] = { 0 };
int k[(maxn << 3) + 5] = { 0 };
//int lzy[(maxn << 2) + 5] = { 0 };
int gcd(int a, int b)
{
while (b != 0)
{
int r = b;
b = a % b;
a = r;
}
return a;
}
int n;
void build(int cl, int cr, int i) {
l[i] = cl; r[i] = cr;
k[i] = 1;
if (cl != cr) {
build(cl, mid(cl, cr), left(i));
build(mid(cl, cr) + 1, cr, right(i));
k[i] = gcd(k[left(i)], k[right(i)]);
}
else scanf("%d", &k[i]);
}
int update(int num, int vol, int i) {
if (l[i]==r[i]) {
k[i] = vol;
return vol;
}
int m = mid(l[i], r[i]);
if (num <= m)
{
return k[i] = gcd(update(num, vol, left(i)), k[right(i)]);
}
else if (num >= (m + 1)) {
return k[i] = gcd(update(num, vol, right(i)), k[left(i)]);
}
}
int cnt;
bool guess(int cl,int cr,int gs,int i){
int m = mid(l[i], r[i]);
if (l[i] == r[i]) { //当前是叶子节点
if( k[i]%gs==0)return true; //当前叶子不需要替换
else //当前叶子需要替换
{
cnt++; //记录需要替换的区间的次数
return cnt <= 1;//如果多于一个那gs就是错的
}
}
if (cl == l[i] && cr == r[i]) {//[l,r]的划分
int kl = k[left(i)];
int kr = k[right(i)];
if (gs==k[i])return true;//能整除
//左边可以被整除则检查有没有可能修改右边为gs
if (kl%gs==0)return guess(m + 1, cr, gs ,right(i));
//右边可以被整除则检查有没有可能修改左边为gs
if(kr%gs==0)return guess(cl, m, gs,left(i));
//都不能被整除
return false;
}
if (cr <= m)//所询问范围全部在左子节点中
{
return guess(cl, cr,gs, left(i));
}
else if (cl >= (m + 1)) {//所询问范围全部在右子结点中
return guess(cl, cr,gs, right(i));
}
else {//所询问范围左右子节点都维护了一部分
return (guess(cl, m, gs,left(i))&&guess(m + 1, cr, gs,right(i)));//这些区间的答案不能有一个是false,而且最多替换一个区间
}
}
int qry;
int a1, a2, a3;
int main() {
scanf("%d", &n);
build(1, n, 1);
int q;
scanf("%d", &q);
for (int i = 0; i < q; ++i) {
scanf("%d", &qry);
if (qry == 1)
{
scanf("%d %d %d", &a1, &a2, &a3);
cnt = 0;
if (guess(a1, a2, a3,1) == true&&cnt<=1)printf("YES");
else printf("NO");
if (i < q - 1)printf("\n");
}
else {
scanf("%d %d", &a1, &a2);
update(a1, a2, 1);
}
}
}