luoguP1438 (分块做法)

思路分析:

  等差数列用线段树是可以维护的,但是当前我们用分块很明显可以很好地维护等差数列的特性。

操作分为三类

准备:对每个块准备begins与mid数组(注意不能使用begin作为变量名或者数组名,因为编译不通过)

1,修改:按照普通分块修改,begins记录这一块的起始位置K,mid记录这一块的公差

void modify(int l,int r,int K,int D){
	int L = l,R = r;
	ll maxVal = (R-L)*D+K; 
	while(l%model!=0&&l<=r){
	  a[l]+=K+(l-L)*D*1ll;
	  l++;
	}
	while((r+1)%model!=0&&r>=l){//这一点一定要记住,r+1!!!! 
	  a[r]+=maxVal-(R-r)*D;
	  r--;
	}
	while(l<=r){
	  begins[l/model]+=K+(l-L)*D*1ll;
	  mid[l/model]+=D;
	  l+=model;
	}
}

2,pushdown操作,这一点为了维护查询的数据正确

void pushdown(int p){
   ll val1 = begins[p],val2 = mid[p];
   for(int i=lb[p];i<=rb[p];i++){
   	  a[i]+=val1;
   	  val1+=val2;
   }
   begins[p]=0;mid[p]=0;
} 

3,查询操作,这就不多说了,主要是pushdown

void query(int x){
	pushdown(x/model);
	printf("%lld\n",a[x]);
}

下面就是总的代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
//常数3*3千万都能100ms过,大概4亿内都能过 
const int maxn = 100005;
const int model = 317;
ll n,m,a[maxn],sum[maxn],size[maxn],begins[model+5],mid[model+5];
vector<ll>G[model+5];
ll lb[maxn],rb[maxn],cnt;
void modify(int l,int r,int K,int D);
void query(int x);
//分块是个非常好的做法,N根号N现在这个算法非常强 ,可以卡过许多东西 
void init(){
	scanf("%lld %lld",&n,&m);
	lb[0]=0;rb[0]=model-1;
	for(int i=1;i<=model-1;i++){
		lb[i] = rb[i-1]+1;
		rb[i] = lb[i]+model-1;
	} 
	for(int i=0;i<n;i++){
	  scanf("%lld",&a[i]);
	  G[i/model].push_back(a[i]);
	}
	for(int i=0;i<=n/model;i++){
		size[i] = G[i].size();
	}
	/*for(int i=0;i<=n/model;i++){
		printf("%d\n",size[i]);
	}*/
}
void work(){
	int opt;
	int l,r,K,D;
	for(int i=1;i<=m;i++){
	   scanf("%d",&opt);
	   if(opt==1){
	   	scanf("%d %d %d %d",&l,&r,&K,&D);
		modify(l-1,r-1,K,D); 
	//	printf("1\n");
	   }
	   if(opt==2){
	   	scanf("%d",&l);
	   	query(l-1);
	   }
	}
}
void pushdown(int p){
   ll val1 = begins[p],val2 = mid[p];
   for(int i=lb[p];i<=rb[p];i++){
   	  a[i]+=val1;
   	  val1+=val2;
   }
   begins[p]=0;mid[p]=0;
} 
void query(int x){
	pushdown(x/model);
	printf("%lld\n",a[x]);
}
void modify(int l,int r,int K,int D){
	int L = l,R = r;
	ll maxVal = (R-L)*D+K; 
	while(l%model!=0&&l<=r){
	  a[l]+=K+(l-L)*D*1ll;
	  l++;
	}
	while((r+1)%model!=0&&r>=l){//这一点一定要记住,r+1!!!! 
	  a[r]+=maxVal-(R-r)*D;
	  r--;
	}
	while(l<=r){
	  begins[l/model]+=K+(l-L)*D*1ll;
	  mid[l/model]+=D;
	  l+=model;
	}
}
int main(){
	//freopen("seq.in","r",stdin);
	//freopen("seq.out","w",stdout); 
	init();
	work();
	return 0;
} 

好啦,感谢观看!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值