914D Bash and a Tough Math Puzzle

传送门

分析

用线段树维护区间gcd,每次查询找到第一个不是x倍数的点,如果这之后还有gcd不能被x整除的区间则这个区间不合法

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int d[2000100],cnt,a[500100];
inline int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
inline void build(int le,int ri,int wh){
      if(le==ri){
          d[wh]=a[le];
          return;
      }
      int mid=(le+ri)>>1;
      build(le,mid,wh<<1); 
      build(mid+1,ri,wh<<1|1);
      d[wh]=gcd(d[wh<<1],d[wh<<1|1]);
      return;
}
inline void update(int le,int ri,int wh,int pl,int k){
      if(le==ri){
          d[wh]=k;
          return;
      }
      int mid=(le+ri)>>1;
      if(mid>=pl)update(le,mid,wh<<1,pl,k);
        else update(mid+1,ri,wh<<1|1,pl,k);
      d[wh]=gcd(d[wh<<1],d[wh<<1|1]);
      return; 
}
inline void q(int le,int ri,int wh,int x,int y,int k){
      if(le>=x&&ri<=y){
          if(d[wh]%k==0)return;
          if(cnt>=1){
            cnt++;
            return;
          }
      }
      if(le==ri){
          cnt++;
          return;
      }
      int mid=(le+ri)>>1;
      if(mid>=x)q(le,mid,wh<<1,x,y,k);
      if(mid<y)q(mid+1,ri,wh<<1|1,x,y,k);
      return;
}
int main(){
      int n,m,i,j,k,x,y,z;
      scanf("%d",&n);
      for(i=1;i<=n;i++)
        scanf("%d
",&a[i]);
      build(1,n,1);
      scanf("%d",&m);
      for(i=1;i<=m;i++){
          scanf("%d",&k);
          if(k==1){
            scanf("%d%d%d",&x,&y,&z);
            cnt=0;
            q(1,n,1,x,y,z);
            if(cnt>1)puts("NO");
              else puts("YES");
          }else {
            scanf("%d%d",&x,&y);
            update(1,n,1,x,y);
          }
      }
      return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9749344.html