D. The Child and Sequence(線段樹+思維)

在這裏插入圖片描述
在這裏插入圖片描述
題目大意:
給你一個序列,你要在這個序列上進行操作。
操作1:1:給定區間[l,r][l,r],對序列中這個區間的所有數ai,i=[l,r]ai,i=[l,r]求和。
操作2:2:給你區間[l,r]x[l,r]和x,對i=[l,r],aii=[l,r],ai mod xx
操作3:3:給你兩個數個數i,k,i,k,ai=kai=k
思路:
注意到m=1e5m=1e5,所以整體時間複雜度O(nlogn)O(nlogn),也就是說你的所以操作時間複雜度不超過O(logn)O(logn)才過通過這個題。注意到區間求和,單點操作用線段樹都可以在O(logn)O(logn)做到,唯一有難度的就是操作對對區間所以數取模。首先考慮一個小小的剪枝,如果某個區間裏面的最大數都<x<x,那麼這個區間不用管了,因爲pp mod x=p,p<xx=p,p<x。當p>x,pp>x,p mod x<=x/2x <= x/2。稍微證明一下。
r=xr = x mod pp
那麼有x=kp+rx = kp + r
k=0,r=x=xk=0,r=x=x mod pp.
k>0,xk>0,x mod p=r<pp = r < p2r/2<(p+r)/2<(kp+r)/2<=x/22r/2<(p+r)/2<(kp+r)/2<=x/2
也就是說對於區間內的每個數xx,對它取mod,這個數至少會減低x/2x/2,那麼我們每次對這個數進行取模,這個數到00的時間複雜度也無非就是O(logx)O(logx),所以整體時間複雜度O(mlogmlogx)O(mlogmlogx),帶兩個loglog是可以過這道題的。
總結:
關於取模這裏,其實不用證明也很容易想到,因爲當xx mod p,x>pp,且x>p,只有當p=x/2p=x/2這個時候才能取到最大值。它在其他地方的取模是對稱的,函數圖像大概是正態分佈的函數圖。對稱軸就是x/2x/2
代碼:

#include<iostream>
using namespace std;
int n,m;
typedef long long int ll;
const int maxn = 1e5 + 10;
struct seg{
	int l,r;
	ll s,m;
	seg(){s = 0,m = 0;}
	seg(int a,int b):l(a),r(b){}
}tree[maxn << 2];
void build(int id,int l,int r){
	if(l == r){
		tree[id] = {l,r};
		scanf("%d",&tree[id].s);
		tree[id].m = tree[id].s;
		return ;
	}
	int mid = l + r >> 1;
	tree[id] = {l,r};
	build(id << 1,l, mid);
	build((id << 1) + 1,mid + 1,r);
	tree[id].s = tree[id << 1].s + tree[(id << 1) + 1].s; 
	tree[id].m = max(tree[id << 1].m , tree[(id << 1) + 1].m);
}
void update(int id,int a,ll b){
	if(tree[id].l == tree[id].r && tree[id].l == a){
		tree[id].s = b;
		tree[id].m = 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].s = tree[id << 1].s + tree[(id << 1) + 1].s;
	tree[id].m = max(tree[id << 1].m,tree[(id << 1) + 1].m);
}
void update2(int id,int l,int r,ll x){
	if(tree[id].m < x)return;
	if(tree[id].l == tree[id].r && tree[id].l >= l && tree[id].r <= r){
		tree[id].s %= x;
		tree[id].m = tree[id].s;	
		return ;
	}
	int mid = tree[id].l + tree[id].r >> 1;
	if(r <= mid)update2(id << 1,l,r,x);
	else if(l > mid)update2((id << 1) + 1,l,r,x);
	else update2(id << 1,l,r,x),update2((id << 1) + 1,l,r,x);
	tree[id].m = max(tree[id << 1].m,tree[(id << 1) + 1].m);
	tree[id].s = tree[id << 1].s + tree[(id << 1) + 1].s;
}
ll query(int id,int l,int r){
	if(tree[id].l >= l && tree[id].r <= r){
		return tree[id].s;
	}
	ll ans = 0;
	int mid = tree[id].l + tree[id].r >> 1;
	if(r <= mid)return ans += query(id << 1,l,r);
	else if(l > mid)return ans += query((id << 1) + 1,l,r);
	else return ans += query(id << 1,l,r) + query((id << 1) + 1,l,r);
}
void solved(){
	scanf("%d%d",&n,&m);
	build(1,1,n);
	int l,r,k,x;
	while(m--){
		int ins;scanf("%d",&ins);
		if(1 == ins){
			scanf("%d%d",&l,&r);
			printf("%lld\n",query(1,l,r));
		}
		if(2 == ins){
			scanf("%d%d%d",&l,&r,&x);
			update2(1,l,r,x);
		}
		if(3 == ins){
			scanf("%d%d",&k,&x);
			update(1,k,x);
		}
	}
}
int main(){
	solved();
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章