http://codeforces.com/problemset/problem/914/D
题意:给你n个数,两种操作:1、询问区间【l,r】在至多一次修改一个数的条件下区间gcd是否等于x。
2、修改第i个数为x。
解法:区间维护gcd,如果该区间gcd%x==0,则该区间算是正确区间,不需要继续递归其儿子。如果该区间gcd%x != 0,递归其儿子。如果递归到叶子儿子说明该点必须改变。减枝:如果需改变的数超过1个则返回。
疑惑:如果某区间gcd为16,问区间gcd是否为2,并存在一个数必须修改,为什么是yes?
答:只需将必须修改的数改为2,区间gcd就变成了2,答案是yes。
//#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string.h>
#include <vector>
#define ME(x , y) memset(x , y , sizeof(x))
#define SF(n) scanf("%d" , &n)
#define rep(i , n) for(int i = 0 ; i < n ; i ++)
#define INF 0x3f3f3f3f
#define mod 20191117
#define PI acos(-1)
#define gcd __gcd
using namespace std;
typedef long long ll ;
int ans ;
struct node
{
int l , r , val ;
}tree[500000<<2];
void build(int l , int r , int root)
{
tree[root].l = l , tree[root].r = r ;
if(l == r)
{
scanf("%d" , &tree[root].val);
return ;
}
int mid = (tree[root].l + tree[root].r) >> 1 ;
build(l , mid , root*2);
build(mid+1 , r , root*2+1);
tree[root].val = gcd(tree[root*2].val , tree[root*2+1].val);
}
void update(int x , int val , int root)
{
if(tree[root].l == tree[root].r)
{
tree[root].val = val ;
return ;
}
int mid = (tree[root].l + tree[root].r) >> 1 ;
if(x <= mid)
update(x , val , root*2);
else{
update(x , val , root*2+1);
}
tree[root].val = gcd(tree[root*2].val , tree[root*2+1].val);
}
void query(int l , int r , int val , int root)
{
if(tree[root].l == tree[root].r)//该点必修改
{
ans++;
return ;
}
if(ans > 1) return ;
int mid = (tree[root].l + tree[root].r) >> 1 ;
if(l <= mid && tree[root*2].val % val != 0)//目标在左儿子区间存在,且左儿子gcd%val!=0,则递归该儿子
query(l , r , val , root*2);
if(r > mid && tree[root*2+1].val % val != 0)
query(l , r , val , root*2+1);
}
int main()
{
int n;
scanf("%d" , &n);
build(1 , n , 1);
int q ;
scanf("%d" , &q);
for(int i = 0 ; i < q ; i++)
{
int t ;
scanf("%d" , &t);
if(t == 2)
{
int x ,val;
scanf("%d%d" , &x , &val);
update(x , val , 1);
}
else{
int l , r , val ;
scanf("%d%d%d" , &l , &r , &val);
ans = 0 ;
query(l , r , val , 1);
if(ans <= 1)
printf("YES
");
else{
printf("NO
");
}
}
}
return 0;
}