5.8 Day4

分块

分块算法,下限低上限高,属于一块大内容。从什么单点修改,到单点查询,再到区间修改,区间查询,再到后来的什么插入删除一个值等等,都可以用分块来做。而分块的每一道题目,几乎都是一个模板,所以,学习分块的时间会比较长,之后的几天,都会有更新博客中的模板。

模板:区间加法,单点查值

代码:
#include 
using namespace std;
const int N=5e4+5;
int n,t,now,l,r,w;
int a[N],add[N],pos[N],ll[N],rr[N];

inline void change(int l,int r,int w)
{
	if (pos[l]==pos[r]) for (register int i=l; i<=r; ++i) a[i]+=w;
	else 
	{
		for (register int i=pos[l]+1; i<=pos[r]-1; ++i) add[i]+=w;
		for (register int i=l; i<=rr[pos[l]]; ++i) a[i]+=w;
		for (register int i=ll[pos[r]]; i<=r; ++i) a[i]+=w;
	}
}

int main(){
	scanf("%d",&n);
	for (register int i=1; i<=n; ++i) scanf("%d",&a[i]);
	
	t=(int)sqrt(n);
	for (register int i=1; i<=t; ++i) ll[i]=(i-1)*t+1,rr[i]=i*t;
	if (rr[t]
此题帮助我理解了分块思想,学会了分块代码结构。

模板:区间加法,区间求和。

代码:
#include 
#define int long long
using namespace std;
const int N=5e4+5;
int n,t,opt,l,r,c;
int a[N],add[N],pos[N],ll[N],rr[N],sum[N],vec[N];

inline void change(int l,int r,int c)
{
	if (pos[l]==pos[r]) for (register int i=l; i<=r; ++i) a[i]+=c,sum[pos[l]]+=c;
	else
	{
		for (register int i=pos[l]+1; i<=pos[r]-1; ++i) add[i]+=c;
		for (register int i=l; i<=rr[pos[l]]; ++i) a[i]+=c,sum[pos[l]]+=c;
		for (register int i=ll[pos[r]]; i<=r; ++i) a[i]+=c,sum[pos[r]]+=c;
	}
}

inline int query(int l,int r,int c)
{
	int ans=0;
	c++;
	if (pos[l]==pos[r])
	{
		for (register int i=l; i<=r; ++i) ans=(ans+a[i]+add[pos[i]])%c;
		return ans;
	}
	else 
	{
		for (register int i=pos[l]+1; i<=pos[r]-1; ++i) ans=(ans+add[i]*vec[i]+sum[i])%c;
		for (register int i=l; i<=rr[pos[l]]; ++i) ans=(ans+a[i]+add[pos[l]])%c;
		for (register int i=ll[pos[r]]; i<=r; ++i) ans=(ans+a[i]+add[pos[r]])%c;
		return ans;
	}
}

signed main(){
	scanf("%lld",&n);
	for (register int i=1; i<=n; ++i) scanf("%lld",&a[i]);
	
	t=(int)sqrt(n);
	for (register int i=1; i<=t; ++i) ll[i]=(i-1)*t+1,rr[i]=i*t;
	if (rr[t]
和上一题相比,稍复杂些即可。

模板:区间开方,区间求和

观察到一个性质:任何在int 范围内的非负数,最多开方5次就会<=1,就能AC此题。
代码:
#include 
#define int long long
using namespace std;
const int N=5e4+5;
int n,t,opt,l,r,c;
int a[N],add[N],pos[N],ll[N],rr[N],sum[N];

inline void change(int l,int r)
{
	if (pos[l]==pos[r]) 
	{
		for (register int i=l; i<=r; ++i) if (a[i]>1) a[i]=(int)sqrt(a[i]);		
		add[pos[l]]=0;
		for (register int i=ll[pos[l]]; i<=rr[pos[l]]; ++i) add[pos[l]]+=a[i];
	}
	else 
	{
		for (register int i=pos[l]+1; i<=pos[r]-1; ++i)
		{
			if (sum[i]==5)continue;
			sum[i]++;
			add[i]=0;
			for (register int j=ll[i]; j<=rr[i]; ++j) a[j]=(int)sqrt(a[j]),add[i]+=a[j];
		}
		for (register int i=l; i<=rr[pos[l]]; ++i) if (a[i]>1) a[i]=(int)sqrt(a[i]);
		add[pos[l]]=0;
		for (register int i=ll[pos[l]]; i<=rr[pos[l]]; ++i) add[pos[l]]+=a[i];
		for (register int i=ll[pos[r]]; i<=r; ++i) if (a[i]>1) a[i]=(int)sqrt(a[i]); 
		add[pos[r]]=0;
		for (register int i=ll[pos[r]]; i<=rr[pos[r]]; ++i) add[pos[r]]+=a[i];
	}
}

inline int query(int l,int r)
{
	int ans=0;
	if (pos[l]==pos[r]) 
	{
		for (register int i=l; i<=r; ++i) ans+=a[i]; 
		return ans;	
	}
	else 
	{
		for (register int i=pos[l]+1; i<=pos[r]-1; ++i) ans+=add[i];
		for (register int i=l; i<=rr[pos[l]]; ++i) ans+=a[i];
		for (register int i=ll[pos[r]]; i<=r; ++i) ans+=a[i];
		return ans;	
	}
}

signed main(){
	scanf("%lld",&n);
	for (register int i=1; i<=n; ++i) scanf("%lld",&a[i]); 
	
	t=(int)sqrt(n);
	for (register int i=1; i<=t; ++i) ll[i]=(i-1)*t+1,rr[i]=i*t;
	if (rr[t]
以上三题应该属于最低等级难度

下面两题要有一定简单的思考。

模板:区间加法,询问区间内小于某个值 的元素个数

代码:
#include 
using namespace std;
const int N=5e4+5;
int n,t,now,opt,l,r,c,begin,end;
int a[N],add[N],ll[N],rr[N],pos[N];
int num[N],sum[N];

inline void change(int l,int r,int c)
{
	if (pos[l]==pos[r]) 
	{
		for (register int i=l; i<=r; ++i) a[i]+=c;
		for (register int i=ll[pos[l]]; i<=rr[pos[l]]; ++i) num[i]=a[i];
		sort(num+ll[pos[l]],num+rr[pos[l]]+1);
	}
	else 
	{
		for (register int i=pos[l]+1; i<=pos[r]-1; ++i) add[i]+=c;
		for (register int i=l; i<=rr[pos[l]]; ++i) a[i]+=c;
		for (register int i=ll[pos[l]]; i<=rr[pos[l]]; ++i) num[i]=a[i];
		sort(num+ll[pos[l]],num+rr[pos[l]]+1);
		for (register int i=ll[pos[r]]; i<=r; ++i) a[i]+=c;
		for (register int i=ll[pos[r]]; i<=rr[pos[r]]; ++i) num[i]=a[i];
		sort(num+ll[pos[r]],num+rr[pos[r]]+1);
	}
}

inline int query(int l,int r,int c)
{
	int ans=0;
	c=c*c;
	if (pos[l]==pos[r])
	{
		for (register int i=l; i<=r; ++i) if (a[i]+add[pos[i]]

模板:区间加法,询问区间内小于某个值 的前驱(比其小的最大元素)

代码:
#include 
using namespace std;
const int N=1e5+5;
int n,t,now,opt,l,r,c,begin,end;
int a[N],add[N],ll[N],rr[N],pos[N];
int num[N],sum[N];

inline void change(int l,int r,int c)
{
	if (pos[l]==pos[r]) 
	{
		for (register int i=l; i<=r; ++i) a[i]+=c;
		for (register int i=ll[pos[l]]; i<=rr[pos[l]]; ++i) num[i]=a[i];
		sort(num+ll[pos[l]],num+rr[pos[l]]+1);
	}
	else 
	{
		for (register int i=pos[l]+1; i<=pos[r]-1; ++i) add[i]+=c;
		for (register int i=l; i<=rr[pos[l]]; ++i) a[i]+=c;
		for (register int i=ll[pos[l]]; i<=rr[pos[l]]; ++i) num[i]=a[i];
		sort(num+ll[pos[l]],num+rr[pos[l]]+1);
		for (register int i=ll[pos[r]]; i<=r; ++i) a[i]+=c;
		for (register int i=ll[pos[r]]; i<=rr[pos[r]]; ++i) num[i]=a[i];
		sort(num+ll[pos[r]],num+rr[pos[r]]+1);
	}
}

inline int query(int l,int r,int c)
{
	int MAX=100000000,ans=-1,poss; 
	if (pos[l]==pos[r])
	{
		for (register int i=l; i<=r; ++i) 
		if (a[i]+add[pos[i]]=c-add[i]) continue; 
			poss=(lower_bound(num+ll[i],num+rr[i]+1,c-add[i])-num)-1; 
			if (c-(num[poss]+add[i])

你可能感兴趣的:(5.8 Day4)