Codecraft-18 and Codeforces Round #458:D,Bash and a Tough Math Puzzle

题目传送门

题目大意:Bash喜欢对数列进行操作。第一种操作是询问l~r区间内的gcd值是否几乎为x,几乎为表示能否至多修改一个数达到。第二种操作是将ai修改为x。总共Q个询问,N个数。

Solution:简单来说,就是对区间gcd值的维护,使用线段树实现。

code:

#include <cstdio>
using namespace std;

int read()
{
    char c;while(c=getchar(),c<'0'||c>'9');
    int x=c-'0';while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
    return x;
}

const int MAXN=5*100000+5;

int N,Q,a[MAXN],o,cnt,x,y,c;
int seg[MAXN*4];

int gcd(int x,int y){return !y?x:gcd(y,x%y);}

void build(int node,int l,int r)
{
    if(l==r)seg[node]=a[l];
    else{
        int mid=l+r>>1;
        build(node<<1,l,mid);
        build(node<<1|1,mid+1,r);
        seg[node]=gcd(seg[node<<1],seg[node<<1|1]);//更行该节点的值
    }
    return ;
}//建树

void change(int node,int l,int r,int dist,int v)
{
    if(l==dist && r==dist){
        seg[node]=v;
        return ;
    }//到达要修改的节点
    int mid=l+r>>1;
    if(mid>=dist)change(node<<1,l,mid,dist,v);
    else         change(node<<1|1,mid+1,r,dist,v);
    seg[node]=gcd(seg[node<<1],seg[node<<1|1]);//更新
    return ;
}

void get(int l,int r,int ql,int qr,int node,int v)
{
    if(cnt>1)return ;//优化
    if(l==r){//此处之所以可以这样,因为我们在搜到这个点之前保证了这个点的seg值%v不为0
        cnt++;
        return ;
    }
    int mid=l+r>>1;
    if(mid>=ql&&seg[node<<1]%v/*此处为上面做法的原因*/)  get(l,mid,ql,qr,node<<1,v);
    if(mid<qr &&seg[node<<1|1]%v)get(mid+1,r,ql,qr,node<<1|1,v);
    return ;
}

void find(int x,int y,int c)
{
    cnt=0;get(1,N,x,y,1,c);
    if(cnt<=1)puts("YES");
    else puts("NO");
    return ;
}

int main()
{
    N=read();
    register int i,j;
        for(i=1;i<=N;i++)a[i]=read();
    build(1,1,N);
    Q=read();
        while(Q--){
            o=read();
            if(o==1){x=read(),y=read(),c=read(),find(x,y,c);}
            else    {x=read(),y=read(),change(1,1,N,x,y);}
        }
    return 0;
}
原文地址:https://www.cnblogs.com/Cptraser/p/8434351.html