北京师范大学第十七届程序设计竞赛决赛-重现赛---慢慢变小的序列(线段树区间更新,区间最小值)

博客围绕慢慢变小的序列问题展开,将公式y*(i - L)+x拆开,发现只有i*L不确定。因y范围是 - 5~5,y + 5范围为0~10,可据此建立多个线段树,用二维数组实现。每次更新第y + 5个线段树的L~R区间的最小值x - y*L,查询时比较ai与y在0~10范围该点的最小值。

慢慢变小的序列

 

思路:

将公式y*(i-L)+x拆开:

i*y + (x-y*L)所以这样只有i*L是不确定的。由于y的范围是-5~5,y+5的范围就是0~10,这11个数,

所以可以根据y的数量建立多个线段树,用二维数组比较方便。

每次更新第y+5个线段树的L~R区间,更新这个点的最小值x-y*L。

查询时,只要比较ai与y在0~10的范围内的在这个点的最小值就行了(因为比较的是最小值,所以即使y位置未被更新也不会对结果产生影响。)

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e9+10;
int tree[12][maxn<<2],lazy[12][maxn<<2],a[maxn],n,q;
void Init(){
	for(int i=0;i<12;i++){
		for(int j=0;j<(maxn<<2);j++){
			tree[i][j] = INF;lazy[i][j] = INF;
		}
	}
}
int MIN(int x,int y){
	return x<y?x:y;
}
void Update(int L,int R,int x,int ta[],int lz[],int rt,int l,int r){
	if(L<=l&&r<=R){
		ta[rt] = MIN(ta[rt],x);
		lz[rt] = MIN(lz[rt],x);
		return ;
	}
	int mid = (l+r)>>1;
	if(lz[rt]!=INF){
		lz[rt<<1] = MIN(lz[rt<<1],lz[rt]);
		lz[rt<<1|1] = MIN(lz[rt<<1|1],lz[rt]);
		ta[rt<<1] = MIN(ta[rt<<1],lz[rt]);
		ta[rt<<1|1] = MIN(ta[rt<<1|1],lz[rt]);
		lz[rt] = INF;
	}
	if(L<=mid) Update(L,R,x,ta,lz,rt<<1,l,mid);
	if(R>mid) Update(L,R,x,ta,lz,rt<<1|1,mid+1,r);
	ta[rt] = MIN(ta[rt<<1],ta[rt<<1|1]);
} 
int Query(int pos,int ta[],int lz[],int rt,int l,int r){
	if(l==r){
		return ta[rt];
	}
	int mid = (l+r)>>1;
	if(lz[rt]!=INF){
		lz[rt<<1] = MIN(lz[rt<<1],lz[rt]);
		lz[rt<<1|1] = MIN(lz[rt<<1|1],lz[rt]);
		ta[rt<<1] = MIN(ta[rt<<1],lz[rt]);
		ta[rt<<1|1] = MIN(ta[rt<<1|1],lz[rt]);
		lz[rt] = INF;
	}
	if(pos<=mid) return Query(pos,ta,lz,rt<<1,l,mid);
	else return Query(pos,ta,lz,rt<<1|1,mid+1,r);
}
int main(void){
	Init();scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	while(q--){
		int op;scanf("%d",&op);
		if(op==2){
			int x;scanf("%d",&x);
			for(int i=0;i<=10;i++){
				a[x] = MIN(a[x],(i-5)*x+Query(x,tree[i],lazy[i],1,1,n));
			}
			printf("%d\n",a[x]);
		}else{
			int l,r,x,y;scanf("%d%d%d%d",&l,&r,&x,&y);
			Update(l,r,x-l*y,tree[y+5],lazy[y+5],1,1,n);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值