Codeforces 914D - Bash and a Tough Math Puzzle 线段树,区间GCD

题意:

两个操作,

单点修改

询问一段区间是否能在至多一次修改后,使得区间$GCD$等于$X$

题解:

正确思路;

线段树维护区间$GCD$,查询$GCD$的时候记录一共访问了多少个$GCD$不被X整除的区间即可,大于一个就NO

要注意的是,如果真的数完一整个区间,肯定会超时,因此用一个外部变量存储数量,一旦超过一个,就停止整个查询

#include <bits/stdc++.h>
#define endl ‘\n‘
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
using namespace std;
int casn,n,m,k;
class segtree{
#define nd  node[now]
#define ndl node[now<<1]
#define ndr node[now<<1|1]
    public:
    struct segnode {
        int l,r;ll gcd,mn;
        int mid(){return (r+l)>>1;}
        int len(){return r-l+1;}
        void update(int x){mn=gcd=x;}
    };
    vector<segnode> node;
    int cnt;
    segtree(int n) {node.resize(n<<2|3);maketree(1,n);}
    void pushup(int now){
        nd.gcd=__gcd(ndl.gcd,ndr.gcd);
        nd.mn=min(ndl.mn,ndr.mn);
    }
    void pushdown(int now){}
    void maketree(int s,int t,int now=1){
        nd={s,t,0,0};
        if(s==t){
            ll x;cin>>x;nd.update(x);
            return ;
        }
        maketree(s,nd.mid(),now<<1);
        maketree(nd.mid()+1,t,now<<1|1);
        pushup(now);
    }
    void update(int pos,ll x,int now=1){
        if(pos>nd.r||pos<nd.l) return ;
        if(nd.len()==1){nd.update(x);return ;}
        pushdown(now);
        update(pos,x,now<<1); update(pos,x,now<<1|1);
        pushup(now);
    }
    int query(int s,int t,ll x){cnt=0;count(s,t,x);return cnt<=1;}
    void count(int s,int t,ll x,int now=1){
        if(cnt>1||s>nd.r||t<nd.l||nd.gcd%x==0) return ;
        if(nd.len()==1) {cnt++; return ;}
        count(s,t,x,now<<1);count(s,t,x,now<<1|1);
    }
};

int main() {
    IO;
    cin>>n;
    segtree tree(n);
    cin>>m;
    while(m--){
        ll a,b,c,d;
        cin>>a;
        if(a==1) {
            cin>>b>>c>>d;
            if(tree.query(b,c,d)) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }else {
            cin>>b>>c;
            tree.update(b,c);
        }
    }
	return 0;
}

错误思路(会WA8):

如果要修改一次使得$GCD$等于$X$,肯定是修改区间的最小值,线段树维护即可

错误原因在于,$GCD$大于$X$的时候,最小值可能是$X$的倍数,此时不应该修改最小值

#include <bits/stdc++.h>
#define endl ‘\n‘
#define ll long long
#define ull unsigned long long
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
#define per(ii,a,b) for(int ii=b;ii>=a;--ii)
#define forn(ii,x) for(int ii=head[x];ii;ii=e[ii].next)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#define inline inline __attribute__(                               (always_inline, __gnu_inline__, __artificial__))                   __attribute__((optimize("Ofast"))) __attribute__((target("sse"))) __attribute__((target("sse2"))) __attribute__((target("mmx")))
#define show(x) cout<<#x<<"="<<x<<endl
#define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl
#define show3(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl
#define show4(w,x,y,z) cout<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl
#define show5(v,w,x,y,z) cout<<#v<<" "<<v<<" "<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl
#define showa(a,b) cout<<#a<<‘[‘<<b<<"]="<<a[b]<<endl
using namespace std;
const int maxn=1e6+10,maxm=2e6+10;
const ll INF=0x3f3f3f3f3f3f;
const int mod=1e9+7;
const double PI=acos(-1.0);
//head
int casn,n,m,k;
int num[maxn];
class segtree{
#define nd  node[now]
#define ndl node[now<<1]
#define ndr node[now<<1|1]
    public:
    struct segnode {
        int l,r;ll gcd,mn;
        int mid(){return (r+l)>>1;}
        int len(){return r-l+1;}
        void update(int x){mn=gcd=x;}
    };
    vector<segnode> node;
    segtree(int n) {node.resize(n<<2|3);maketree(1,n);}
    void pushup(int now){
        nd.gcd=__gcd(ndl.gcd,ndr.gcd);
        nd.mn=min(ndl.mn,ndr.mn);
    }
    void pushdown(int now){}
    void maketree(int s,int t,int now=1){
        nd={s,t,0,0};
        if(s==t){
            ll x;cin>>x;nd.update(x);
            return ;
        }
        maketree(s,nd.mid(),now<<1);
        maketree(nd.mid()+1,t,now<<1|1);
        pushup(now);
    }
    void update(int pos,ll x,int now=1){
        if(pos>nd.r||pos<nd.l) return ;
        if(nd.len()==1){nd.update(x);return ;}
        pushdown(now);
        update(pos,x,now<<1); update(pos,x,now<<1|1);
        pushup(now);
    }
    ll query_minid(int s,int t,int now=1){
        if(nd.len()==1) return s;
        if(ndl.mn<=ndr.mn) return query_minid(s,t,now<<1);
        else return query_minid(s,t,now<<1|1);
    }
    ll query_min(int s,int t,int now=1){
        if(s>nd.r||t<nd.l) return INF;
        if(s<=nd.l&&nd.r<=t) return nd.mn;
        return min(query_min(s,t,now<<1),query_min(s,t,now<<1|1));
    }
    ll query_gcd(int s,int t,int now=1){
        if(s>nd.r||t<nd.l) return 0;
        if(s<=nd.l&&t>=nd.r)return nd.gcd;
        return __gcd(query_gcd(s,t,now<<1),query_gcd(s,t,now<<1|1));
    }
};

int main() {
//#define test
#ifdef test
	auto _start = chrono::high_resolution_clock::now();
	freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif
//    IO;
    cin>>n;
    segtree tree(n);
    cin>>m;
    while(m--){
        ll a,b,c,d;
        cin>>a;
        if(a==1) {
            cin>>b>>c>>d;
            int id=tree.query_minid(b,c);
            ll mn=tree.query_min(b,c);
            tree.update(id,d);
            if(tree.query_gcd(b,c)==d)cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
            tree.update(id,mn);
        }else {
            cin>>b>>c;
            tree.update(b,c);
        }
    }
	return 0;
}

原文地址:https://www.cnblogs.com/nervendnig/p/10227074.html

时间: 2024-08-28 19:34:27

Codeforces 914D - Bash and a Tough Math Puzzle 线段树,区间GCD的相关文章

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>

Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论

Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论 题意 给你一段数,然后小明去猜某一区间内的gcd,这里不一定是准确值,如果在这个区间内改变一个数的值(注意不是真的改变),使得这个区间的gcd是小明所猜的数也算小明猜对.另一种操作就是真的修改某一点的值. 解题思路 这里我们使用线段树,维护区间内的gcd,判断的时候需要判断这个区间的左右子区间的gcd是不是小明猜的数的倍数或者就是小明猜的数,如果是,那么小明猜对了.否则就需要进入这个区间

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';whi

codeforces 914 D Bash and a Tough Math Puzzle

1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstdio> 6 using namespace std; 7 const int N=500100; 8 int n,a[N],m; 9 struct tree{ 10 int l,r,gcd; 11 }tr[N*5]; 12 int gcd(int x,in

[CF914D]Bash and a Tough Math Puzzle

给定一个数列$a_1,a_2,...,a_n$?,支持两种操作 1 l r x,猜测数列中[l,r]位置上的数的最大公约数$x$,判断这个猜测是否是接近正确的.如果我们可以在数列[l,r]位置中改动至多一个数使得它们的最大公约数是x,那么这个猜测就被认为是接近正确的(注意我们不需要在数列中进行实际的改动).如果这个猜测是接近正确的,输出"YES",否则输出"NO"(都不含引号). 2 i y,将$a_i$的数值改为y. 如果这一段区间有超过一个数不是$x$的倍数就不

Codeforces 458C Elections 贿赂选票抢主席! 线段树

题目链接:点击打开链接 题意: 给定n张选票,每张选票有2个参数,第一个参数表示这张选票选的人 第二个参数表示如果让这张选票改为选0号 的花费 问:使得0号的选票是最高的(不能有和0号相同)的最小花费 枚举0号的最终选票 那么已知0号最终选票,则有些人选票比0号大的,那些票都要买下来. 如果买完了还是达不到 最终选票,就从所有剩下的选票里找前k小的. 用线段树求前k小的数的和,然后_(:зゝ∠)_就可以了 #include<iostream> #include<cstdio> #i

Codeforces 1136E Nastya Hasn&#39;t Written a Legend (线段树教做人系列)

题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后,a[i + 1]<a[i] + k[i],那么a[i + 1]就变成a[i] + k[i],否则不变.同理,若a[i + 2]小于了现在的a[i + 1] + k[i + 1],那么a[i + 2]也变成a[i + 1] + k[i + 1],一直保持这个性质.第二章操作,询问数组a的区间[l, r]的

codeforces 482B. Interesting Array【线段树区间更新】

题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val.就是区间l---r上的与的值为val,最后问你原来的数组是多少?如果不存在输出no 分析:分析发现要满足所有的区间,而一个点上假如有多个区间的话,这个点的值就是所有区间或的值,因为只有这样才能满足所有区间的,把所有位上的1都保存下来了,那么可以发现用线段树来维护,但是那么怎么判断满不满足条件呢?可以也用线段树,更新了之后在整个维护一遍看看满不满足题意,如

Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq

B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/427/B Description The prison of your city has n prisoners. As the prison can't accommodate all of them, the city mayor has decided to transfer c