Codecraft-18 and Codeforces Round #458 (Div. 1 + Div. 2, combined) D. Bash and a Tough Math Puzzle 线段树|gcd的可结合性

首先注意到gcd是满足结合率的,所以可以用线段树维护区间gcd

然后简单讨论一下什么时候只要删掉一个就可以

1,如果左区间和右区间的gcd都为x的倍数,直接return true

2,如果都不是,也都直接return false

3,如果有一个是,那么转化为子问题继续递归,出口是l==r(只能删一个)

最开始写法是把查区间gcd和判断是否有解的函数放一起写,发现很难写,so这个还是要理清晰

ps.有个笨蛋,build时把t[rt].l=l,t[rt].r=r写在if里面惹,是谁,我不说:)

复制代码
#include<bits/stdc++.h>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int maxn=5*1e5+5;
int a[maxn],n,q;
struct seg{
    int l,r,g;
    //
}t[maxn<<2];
int gcd(int x,int  y){
   return x%y==0?y:gcd(y,x%y);
}
void push_up(int rt){
    //
    t[rt].g=gcd(t[ls].g,t[rs].g);
}
void build(int rt,int l,int r){
    t[rt].l=l;t[rt].r=r;
    if(l==r){
       //
       t[rt].g=a[l];
       return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);build(rs,mid+1,r);
    push_up(rt);
}
void update(int rt,int l,int r,int val){
    if(l<=t[rt].l&&t[rt].r<=r){
        // update
        t[rt].g=val;
        return;
    }
    if(t[ls].r>=l) update(ls,l,r,val);
    if(t[rs].l<=r) update(rs,l,r,val);
    push_up(rt);
}
int query(int rt,int l,int r){
    if(l<=t[rt].l&&t[rt].r<=r){
        return t[rt].g;
    }
    int ans=0;
    if(t[ls].r>=l) ans=query(ls,l,r);//
    if(t[rs].l<=r) {
        if(ans==0) ans=query(rs,l,r);
        else ans=gcd(ans,query(rs,l,r));
    }
    return ans;
}
bool ask(int rt,int l,int r,int x){
    if(t[rt].l==t[rt].r){
        return true;//
    }
    int ans1=x,ans2=x;
    if(t[ls].r>=l) ans1=gcd(ans1,query(ls,l,r));
    if(t[rs].l<=r) ans2=gcd(ans2,query(rs,l,r));
    if(ans1==x&&ans2==x) return true;
    else if(ans1!=x&&ans2!=x) return false;
    else {
        if(ans1==x) return ask(rs,l,r,x);
        else return ask(ls,l,r,x);
    }
} 
int main(){
    //freopen("lys.in","r",stdin);
    fastio;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n);
    cin>>q;
    for(int i=1;i<=q;i++){
        int op;cin>>op;
        if(op==1){
            int L,R,x;
            cin>>L>>R>>x;
            if(ask(1,L,R,x)) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
        else {
            int id,y;
            cin>>id>>y;
            update(1,id,id,y);
        }
    }
}
复制代码

 

posted @   liyishui  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示