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; }