CF914D Bash and a Tough Math Puzzle 线段树+gcd??奇怪而精妙

嗯~~,好题。。。

用线段树维护区间gcd,按如下法则递归:(记题目中猜测的那个数为x,改动次数为tot)

  1.若子区间的gcd是x的倍数,不递归;

  2.若子区间的gcd不是x的倍数,且没有递归到叶子结点,那么向下递归

  3.若递归到叶子结点,说明这个数需要改动,++tot

  4.若在任意时刻有tot>1,则直接return(不符题意)

#include<cstdio>
#include<iostream>
#define ll long long
#define R register int
#define pc(x) putchar(x)
#define ls (tr<<1)
#define rs (tr<<1|1)
const int M=500010;
using namespace std;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,m,tot;
int sum[M<<2];
inline int gcd(int a,int b) {return b?gcd(b,a%b):a;}
inline void build(int tr,int l,int r) {
    if(l==r) {sum[tr]=g(); return ;} R md=(l+r)>>1;
    build(ls,l,md),build(rs,md+1,r); sum[tr]=gcd(sum[ls],sum[rs]);
}
inline void update(int tr,int l,int r,int pos,int inc) {
    if(l==r) {sum[tr]=inc; return ;} R md=(l+r)>>1;
    if(pos<=md) update(ls,l,md,pos,inc); else update(rs,md+1,r,pos,inc);
    sum[tr]=gcd(sum[ls],sum[rs]);
}
inline void query(int tr,int l,int r,int LL,int RR,int mod) {
    if(tot>1) return ; if(l==r) { ++tot; return ;} R md=(l+r)>>1;
    if(LL<=md&&sum[ls]%mod) query(ls,l,md,LL,RR,mod); if(RR>md&&sum[rs]%mod) query(rs,md+1,r,LL,RR,mod);
}
signed main() {
    n=g(); build(1,1,n); m=g();
    for(R i=1;i<=m;++i) {
        R k=g(),l=g(),r=g(),mod;
        if(k&1) {
            mod=g(),tot=0,query(1,1,n,l,r,mod); 
            tot>1?(pc('N'),pc('O')):(pc('Y'),pc('E'),pc('S')); pc('\n');
        } else update(1,1,n,l,r);
    }
}

2019.04.19

转载于:https://www.cnblogs.com/Jackpei/p/10738991.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值