數學+線段樹 小陽的貝殼(牛客小白月賽16 H題)

小陽的貝殼

題目大意:
給你一個長度爲n的數組,有初值,三種操作;

  1. 給區間[l,r]所有數加上x;
  2. 詢問區間[l,r]相鄰的元素差值最大值(取絕對值);
  3. 詢問區間[l,r]所有數的最大公約數;

最難的就是第三問了,運用到了gcd的一些原理,如果不是很懂得話想不到;

gcd(a,b,c)=gcd(a,b-a,c-b)=gcd(a,gcd(b-a,c-b));

依此類推,不就是維護一個差分數組,如果求[l,r]的最大公約數,不就是求

gcd(a[l],gcd(b[l+1]…b[r]));(a[]代表原數組,b[]代表差分數組)

代碼:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=100100;
const int M=2000000;
const LL mod=1e9+7;
int n,m,a[N];
struct Node{
	int l,r,sum,mx,mg;
}tr[N*4];
void pp(int k){
	tr[k].mx=max(tr[ls].mx,tr[rs].mx);
	tr[k].mg=__gcd(tr[ls].mg,tr[rs].mg);
	tr[k].sum=tr[ls].sum+tr[rs].sum;
}
void build(int l,int r,int k){
	tr[k].l=l,tr[k].r=r;
	if(l==r){
		tr[k].mx=tr[k].mg=abs(a[l]);
		tr[k].sum=a[l];
		return;
	}
	int d=(l+r)>>1;
	build(l,d,ls);build(d+1,r,rs);
	pp(k);
}
void update(int pos,int w,int k){
	if(tr[k].l==tr[k].r){
		a[tr[k].l]+=w;
		tr[k].sum=a[tr[k].l];
		tr[k].mx=tr[k].mg=abs(a[tr[k].l]);
		return;
	}
	int d=(tr[k].l+tr[k].r)>>1;
	if(pos<=d) update(pos,w,ls);
	else update(pos,w,rs);
	pp(k);
}
int query_max(int l,int r,int k){
	if(l>r) return 0;
	if(tr[k].l>=l&&tr[k].r<=r) return tr[k].mx;
	int mx=0;
	int d=(tr[k].l+tr[k].r)>>1;
	if(l<=d) mx=max(query_max(l,r,ls),mx);
	if(r>d) mx=max(query_max(l,r,rs),mx);
	return mx;
}
int query_sum(int l,int r,int k){
	if(tr[k].l>=l&&tr[k].r<=r) return tr[k].sum;
	int sum=0;
	int d=(tr[k].l+tr[k].r)>>1;
	if(l<=d) sum+=query_sum(l,r,ls);
	if(r>d) sum+=query_sum(l,r,rs);
	return sum;
}
int query_gcd(int l,int r,int k){
	if(tr[k].l>=l&&tr[k].r<=r) return tr[k].mg;
	int mg=0;
	int d=(tr[k].l+tr[k].r)>>1;
	if(l<=d) mg=__gcd(mg,query_gcd(l,r,ls));
	if(r>d) mg=__gcd(mg,query_gcd(l,r,rs));
	return mg;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=n;i>=1;i--) a[i]-=a[i-1];//差分數組 
	build(1,n,1);
	for(int i=1;i<=m;i++){
		int opt;scanf("%d",&opt);
		if(opt==1){
			int l,r,x;scanf("%d%d%d",&l,&r,&x);
			update(l,x,1);//單點更新 
			if(r<n) update(r+1,-x,1);//單點更新 
		}
		else if(opt==2){
			int l,r;scanf("%d%d",&l,&r);
			printf("%d\n",query_max(l+1,r,1));
		}
		else{
			int l,r;scanf("%d%d",&l,&r);
			printf("%d\n",__gcd(query_sum(1,l,1),query_gcd(l+1,r,1)));
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章