codeforces 914 D. Bash and a Tough Math Puzzle(线段树 区间gcd)

本文解析了CodeForces上的一道题目,采用线段树维护区间最大公约数的策略,实现快速查询和更新,以判断区间内的数通过改变一个元素是否能使最大公约数等于指定值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://codeforces.com/problemset/problem/914/D

题意:给出一个数组,现有两种操作
1.给出l,r,x 询问在l,r区间内至多改变一个数,gcd能否为x
2.单点修改元素值

思路:考虑线段树维护,最麻烦的是改变一个元素后gcd能否为x,首先线段树维护每个区间的gcd,首先父节点储存的gcd如果能都整除x,那么该区间gcd就可以在改变一个数的情况下为x
比如 x=2 查询区间数值为 4 8 12 4,任意改变一个数为2即符合题意。
如果该父亲区间不能整除x,那么继续往下寻找到叶子节点,找到不能整除x的叶子节点,假设将其改变为x,并且记录数目,因为我们只能改一个,那么如果大于一个直接不合法,所以我们最多找到2个不满足条件的数递归结束,所以时间复杂度可以满足要求

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<"Here is "<<a<<endl;
#define show2(a,b) cout<<"Here is "<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<"Here is "<<a<<" "<<b<<" "<<c<<endl;
using namespace std;

typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const ll inf = 1e17 + 10;
const int N = 3e6 + 10;
const ll mod = 10007;
const int base=131;

int n,block,m,id,t,x;
int bl[N],cnt;
ll a[N],k;
ll ans,res[N];
ll tree[N];
//unordered_map<int,int> mp;
tr1::unordered_map<ll,int> num;

void pushup(int rt)
{
	tree[rt]=__gcd(tree[rt<<1],tree[rt<<1|1]);
}
void build(int l,int r,int rt)
{
	if(l==r)
	{
		cin>>tree[rt];
		return ;
	}
	int m=l+r >> 1;
	build(l,m,rt<<1);
	build(m+1,r,rt<<1|1);
	pushup(rt);
}
bool query(int L,int R,int x,int l,int r,int rt)
{
	if(tree[rt]%x==0) return 1;
	if(l==r) return --cnt>=0;
	int m=l+r >> 1;
	if(R<=m) return query(L,R,x,l,m,rt<<1);
	else if(L>=m+1) return query(L,R,x,m+1,r,rt<<1|1);
	else return (query(L,R,x,l,m,rt<<1)&&query(L,R,x,m+1,r,rt<<1|1));
}

void update(int pos,int x,int l,int r,int rt)
{
	if(l==r)
	{
		tree[rt]=x;
		return ;
	}
	int m=l+r >> 1;
	if(pos<=m) update(pos,x,l,m,rt<<1);
	else update(pos,x,m+1,r,rt<<1|1);
	pushup(rt);
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	cin>>n;
	build(1,n,1);
	cin>>t;
	int l,r;
	while(t--)
	{
		cin>>k;
		if(k==1)
		{
			cnt=1;
			cin>>l>>r>>x;
			if(query(l,r,x,1,n,1)) cout<<"YES"<<endl;
			else cout<<"NO"<<endl;
		}
		else
		{
			cin>>id>>x;
			update(id,x,1,n,1);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值