Codeforces Round #458 D. Bash and a Tough Math Puzzle---线段树

题目:http://codeforces.com/contest/914/problem/D

题意:有查询和更新两个操作,更新是直接把某个值更新为给定值,查询是查询给定区间上的最大公约数(GCD),如果最大公约数是题中所给值(x)或者通过更改区间上的一个值可以使该区间的GCD变成x,则输出YES,不然输出NO。

题解:用线段树维护区间上的GCD,更新就是单点更新,而查询操作emm...看代码注释吧

代码:

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define ls id*2
#define rs id*2+1
#define mid (tree[id].l+tree[id].r)/2
const int maxn=1e6+1e5+10;

ll gcd(ll a,ll b){
	return b==0?a:gcd(b,a%b);
}

struct node{
	ll l,r,v;
}tree[maxn];

ll cnt=0,n;

void pushup(ll id){
	tree[id].v=gcd(tree[ls].v,tree[rs].v);
}

void build(ll id,ll L,ll R){
	tree[id].l=L;
	tree[id].r=R;
	if(L==R){
		scanf("%I64d",&tree[id].v);
		return;
	}
	build(ls,L,mid);
	build(rs,mid+1,R);
	pushup(id);
}

void update(ll i,ll y,ll id){//单点更新 
	if(tree[id].l==tree[id].r){
		tree[id].v=y;
		return;
	}
	if(i<=mid) update(i,y,ls);
	else update(i,y,rs);
	pushup(id);
}

void query(ll id,ll L,ll R,ll x){//查询  
	if(cnt>=2) return;
	//计数要更改的值的个数,超过2时直接返回,输出结果为NO 
	if(tree[id].l==tree[id].r){
	//更新到叶子节点,如果这个值需要更改的话,cnt++ 
		if(tree[id].v%x!=0){
			cnt++;
		}
		return;
	}
	if(L<=tree[id].l&&R>=tree[id].r){
	//对于包含在查询区间里的线段,如果这一段的值不等于x,则说明这个线段里存在需要更改的值  
		if(tree[id].v!=x){
			//直接暴力更新到叶子节点会T ,所以分左右来更新 
			//因为这一段的GCD已经不等于x,则其左右子节点至少有一个不能被x整除 (注意不是等于x )  
			if(tree[ls].v%x==0) query(rs,L,R,x); //左边能整除说明要更改的值一定在右边,下同理 
			else if(tree[rs].v%x==0) query(ls,L,R,x) 
			else cnt=2;//两边都不能说明至少有两个值需要更新,输出NO 
		} 
		return;
	}
	if(L<=mid) query(ls,L,R,x);
	if(R>mid) query(rs,L,R,x);
}


int main(){
	scanf("%I64d",&n);
	build(1,1,n);
	ll m,b,c,d,e;
	scanf("%I64d",&m);
	while(m--){
		scanf("%I64d%I64d%I64d",&b,&c,&d);
		if(b==1){
			scanf("%I64d",&e);
			cnt=0;
			query(1,c,d,e);
		//	cout<<cnt<<endl;
			if(cnt<=1) printf("YES\n");
			else printf("NO\n");
		}
		else{
			update(c,d,1);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值