分块

题目链接

题意:就是单点更新 区间查询最小值

线段树做法:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
typedef long long LL;
LL tree[N<<2];
const int inf=0x3f3f3f3f; 
void build(int l,int r,int k)
{
	if(l==r){
		tree[k]=0;
		return;
	}
	int mid=(l+r)>>1;
	build(1,mid,k<<1);
	build(mid+1,r,k<<1|1);
}
void update(int x,LL z,int l,int r,int k)
{
	if(l==r){
		tree[k]+=z;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) update(x,z,l,mid,k<<1);
	else update(x,z,mid+1,r,k<<1|1);
	tree[k]=max(tree[k<<1],tree[k<<1|1]);
}
LL query(int x,int y,int l,int r,int k)
{
	if(x<=l&&y>=r){
		return tree[k];
	}
	int mid=(l+r)>>1;
	LL  minn=0;
	if(x<=mid) minn=max(minn,query(x,y,l,mid,k<<1));
	if(y>mid) minn=max(minn,query(x,y,mid+1,r,k<<1|1));
	return minn;
	
}
int main()
{
	int n,q;scanf("%d %d",&n,&q);
	while(q--){
		int id;
		scanf("%d",&id);
		if(id==1){
			int x;
			LL y;
			scanf("%d %lld",&x,&y);
			update(x,y,1,n,1);
		}
		else{
			int a,b;
			scanf("%d %d",&a,&b);
			printf("%lld\n",query(a,b,1,n,1));
		}
	}
	return 0;
}

 

 

分块做法比较简单  好理解  

分块是一个在线算法 不是莫队那种离线算法

分块可以处理区间奇奇怪怪的操作

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int block;//块的大小 
int belong[N];//表示i属于那一块 
int num;//块的个数 
int l[N],r[N];//表示i这块的左右端点位置 
int n,q;
long long a[N],maxn[N];
void build()
{
	block=sqrt(n);
	num=n/block;
	if(n%block) num++;
	for(int i=1;i<=num;i++){
		l[i]=(i-1)*block+1;
		r[i]=i*block;
	}
	r[num]=n;
	for(int i=1;i<=n;i++){
		belong[i]=(i-1)/block+1;
	}
	
	//这部分没有用到 因为没有给a[i]初始值 这里的初始值为0 
	for(int i=1;i<=num;i++){
		for(int j=l[i];j<=r[i];j++){
			maxn[i]=max(maxn[i],a[j]);
		}
	}
}

void update(int x,int y)
{
	a[x]+=y;
	maxn[belong[x]]=max(maxn[belong[x]],a[x]);
	
}
long long query(int x,int y)
{
	long long ans=0;
	if(belong[x]==belong[y]){
		for(int i=x;i<=y;i++){
			ans=max(ans,a[i]);
		}
		return ans;
	}
	for(int i=x;i<=r[belong[x]];i++){
		ans=max(ans,a[i]);
	}
	for(int i=belong[x]+1;i<belong[y];i++){
		ans=max(ans,maxn[i]);
	}
	for(int i=l[belong[y]];i<=y;i++){
		ans=max(ans,a[i]);
	}
	return ans;
}
int main()
{
	scanf("%d %d",&n,&q);
	build();
	while(q--){
		long long t,x,y;
		scanf("%lld %lld %lld",&t,&x,&y);
		if(t==1){
			update(x,y); 
		} 
		else{
			printf("%lld\n",query(x,y));
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值