codeforces 914 D 线段树+数学

题意

给出一个长度为\(n\)的数列\(a\),两种询问,第一种给出三个数\(l,r,x\),区间\([l,r]\)\(gcd\)值是否和\(x\)相似,若最多改变区间\([l,r]\)中的一个数使区间\([l,r]\)\(gcd\)值等于\(x\),则相似,第二种给出两个数\(i,y\),将\(a[i]\)变为\(y\)

分析

建一个线段树维护区间\(gcd\),这个线段树非常好写,因为是单点修改,所以不需要tag数组和pushdown,查询的时候用一个变量\(cnt\),记录区间\([l,r]\)中有多少个数不是\(x\)的倍数,\(cnt>1\)时直接跳出。

Code

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    const double PI=acos(-1.0);
    const double eps=1e-6;
    const int inf=1e9;
    const int mod=1e9+7;
    const int maxn=5e5+10;
    int n,a[maxn];
    int ans[maxn*5];
    int gcd(int a,int b){
        return b==0?a:gcd(b,a%b);
    }
    void pushup(int p){
        ans[p]=gcd(ans[p<<1],ans[p<<1|1]);
    }
    void build(int l,int r,int p){
        if(l==r){
            ans[p]=a[l];
            return;
        }
        int mid=l+r>>1;
        build(l,mid,p<<1);
        build(mid+1,r,p<<1|1);
        pushup(p);
    }
    void update(int dl,int dr,int l,int r,int p,int k){
        if(l>=dl&&r<=dr){
            ans[p]=k;
            return;
        }
        int mid=l+r>>1;
        if(dl<=mid) update(dl,dr,l,mid,p<<1,k);
        if(dr>mid) update(dl,dr,mid+1,r,p<<1|1,k);
        pushup(p);
    }
    int cnt;
    bool query(int dl,int dr,int l,int r,int p,int x){
        if(l>=dl&&r<=dr){
            if(ans[p]%x==0) {//这个区间的gcd是x的倍数时直接返回true,否则继续向下查询
                return true;
            }
            if(l==r){//这个数不是x的倍数,cnt++
                cnt++;
                if(cnt>1) return false;
                return true;
            }
        }
        int mid=l+r>>1;
        if(dl<=mid) if(!query(dl,dr,l,mid,p<<1,x)) return false;
        if(dr>mid) if(!query(dl,dr,mid+1,r,p<<1|1,x)) return false;
        return true;
    }
    int main(){
        //ios::sync_with_stdio(false);
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        build(1,n,1);
        int q;
        scanf("%d",&q);
        while(q--){
            int op,l,r,x,i,y;
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d%d",&l,&r,&x);
                cnt=0;
                if(query(l,r,1,n,1,x)){
                    puts("YES");
                }else{
                    puts("NO");
                }
            }else{
                scanf("%d%d",&i,&y);
                update(i,i,1,n,1,y);
            }
        }
        return 0;
    }
全部评论

相关推荐

一个菜鸡罢了:哥们,感觉你的简历还是有点问题的,我提几点建议,看看能不能提供一点帮助 1. ”新余学院“别加粗,课程不清楚是否有必要写,感觉版面不如拿来写一下做过的事情,教育经历是你的弱势就尽量少写 2. “干部及社团经历”和“自我评价”删掉 3. 论文后面的“录用”和“小修”啥的都删掉,默认全录用,问了再说,反正小修毕业前肯定能发出来 4. 工作经验和研究成果没有体现你的个人贡献,着重包装一下个人贡献
点赞 评论 收藏
分享
粗心的雪碧不放弃:纯学历问题,我这几个月也是一直优化自己的简历,后来发现优化到我自己都觉得牛逼的时候,发现面试数量也没有提升,真就纯学历问题
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务