D Bash and a Tough Math Puzzle(線段樹+思維+剪枝)

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
題目大意:
給你一個序列,你要在這個序列上進行mm次操作,操作1:l,r,x1:l,r,x表示判斷是否序列區間[l,r][l,r]中所有數的gcd()=xgcd()=x,如果不等於你可以修改其中一個數的值。操作2:i,yai=y2:i,y將ai= y
思路:
注意到q=4e5q=4e5也就是說你的所有操作要在O(logn)O(logn)內完成才能通過這題,所以我們考慮採用線段樹來解決這題。操作二比較簡單就是基礎的單點修改,我們來考慮一下操作一,當gcd(l,r)gcd(l,r) mod x=0x = 0也就是說這個區間內所有的數都是xx的倍數,那麼我們隨便修改其中一個數爲xx,就會有整體的gcd=xgcd=x.當一個區間gcd(li,ri)gcd(li,ri) mod x!=0x!=0,也就是說這個區間至少有一個數不是xx的倍數。但是我們無法確定是哪個數,所有我們需要遞歸要葉子節點才能確定,如果到達葉子節點並且這個節點 mod x!=0x!=0,說明要想使得gcd(l,r)=xgcd(l,r)=x那麼這個數必須要修改,我們用cntcnt來統計需要修改的節點個數。如果當前區間左右兒子都不是xx的倍數必要要修改兩個數,我們直接剪枝令cnt=2returncnt=2,return。最後根據cntcnt來輸出就行了。
總結:線段樹維護區間gcdgcd。利用gcdgcd性質剪枝以及思考,總體不是很難。還有需要注意的就是當一個區間gcd[li,ri]gcd[li,ri] mod x!=0x!=0,需要一直遞歸到葉子節點才能判斷,不能直接cnt++cnt++,因爲可能在某一個子區間有左右兒子 mod xx都不等於0。
代碼:

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

const int maxn = 5e5 + 10;
typedef long long int ll;
struct seg{
	int l,r;
	int gcd;
	seg(){}
	seg(int a,int b):l(a),r(b){}
}tree[maxn << 2];
void build(int id,int l,int r){
	tree[id] = {l,r};
	if(l == r){
		scanf("%d",&tree[id].gcd);
		return ;
	}
	int mid = l + r >> 1;
	build(id << 1,l,mid);
	build((id << 1) + 1,mid + 1, r);
	tree[id].gcd = __gcd(tree[id << 1].gcd,tree[(id << 1) + 1].gcd);
}	
void update(int id,int a,int b){
	if(tree[id].l == tree[id].r && tree[id].l == a){
		tree[id].gcd = b;
		return ;
	}
	int mid = tree[id].l + tree[id].r >> 1;
	if(a <= mid)update(id << 1,a,b);
	else update((id << 1) + 1,a,b);
	tree[id].gcd = __gcd(tree[id << 1].gcd,tree[(id << 1) + 1].gcd);
}
void query(int id,int l,int r,int x,int &cnt){
	if(cnt >= 2){return;}	
	if(tree[id].l >= l && tree[id].r <= r){
		if(tree[id].gcd % x == 0)return ;
		else if(tree[id].l == tree[id].r){cnt++;return;}
		if(tree[id << 1].gcd % x != 0 && tree[(id << 1) + 1].gcd % x != 0){
			cnt = 2;return;
		}
		if(tree[id << 1].gcd % x != 0)
		query(id << 1,l,r,x,cnt);
		if(tree[(id << 1) + 1].gcd % x != 0)
		query((id << 1) + 1,l,r,x,cnt);
		return;
	}
	int mid = tree[id].l + tree[id].r >> 1;
	if(r <= mid) query(id << 1,l,r,x,cnt);
	else if(l > mid) query((id << 1) + 1,l,r,x,cnt);
	else query(id << 1,l,r,x,cnt) , query((id << 1) + 1,l,r,x,cnt);
}
void solved(){
	int n;scanf("%d",&n);
	build(1,1,n);
	int q;scanf("%d",&q);
	int l,r,x;
	while(q--){
		int ins;scanf("%d",&ins);
		if(ins == 1){
			int cnt = 0;
			scanf("%d%d%d",&l,&r,&x);
			if(l == r){cout<<"YES"<<endl;continue;}
			query(1,l,r,x,cnt);
			if(cnt <= 1)printf("YES\n");
			else printf("NO\n");
		}
		if(ins == 2){
			ll i,y;
			scanf("%lld%lld",&i,&y);
			update(1,i,y);
		}
	}
}
int main(){
	solved();
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章