区间gcd

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;
}
原文地址:https://www.cnblogs.com/nonames/p/11955588.html