[HDU5828]Rikka with Sequence

Posted jefflyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HDU5828]Rikka with Sequence相关的知识,希望对你有一定的参考价值。

题意:维护一个数列,支持区间加,区间开根下取整,区间求和

最暴力的想法当然是用线段树维护,对于开根,如果当前区间内的数全相同,那么打一个覆盖标记,否则递归处理

这样当然是会被卡掉的:对于数列$\\{2,3,2,3,\\cdots\\}$,重复$+6$和开根操作,这样就可以把上面那种暴力做法卡掉了

但其实这种暴力已经离正解很近了,考虑维护区间极差,如果递归到当前区间的极差$\\geq2$,那么按暴力的方法做,否则分情况打一个区间减标记或者覆盖标记

为什么这样是对的?不妨设区间最小值为$mn$,最大值为$mx$,且$mx-mn\\geq2$,那么$\\left\\lfloor\\sqrt{mx+d}\\right\\rfloor-\\left\\lfloor\\sqrt{mn+d}\\right\\rfloor=\\left\\lfloor\\sqrt{mn+d+(mx-mn)}\\right\\rfloor-\\left\\lfloor\\sqrt{mn+d}\\right\\rfloor$

考虑函数$f(x)=\\left\\lfloor\\sqrt{x}\\right\\rfloor$

技术分享图片

容易发现对任意的$d\\geq2$,$f(x+d)-f(x)\\lt d$

有了这个结论,上面的式子告诉我们一段极差$\\geq2$的数开根下取整后极差会变小,而且开根本来就让数字减小得很快,所以对极差$\\geq2$的区间,暴力也可以保证复杂度

那个用来卡暴力的数据告诉我们极差$=1$的情况要特别处理,如果$\\sqrt{mx}=\\sqrt{mn}$,打上覆盖标记,如果$\\sqrt{mx}=\\sqrt{mn}+1$,打上区间减标记

#include<stdio.h>
#include<math.h>
#define ll long long
#define inf 9223372036854775807ll
int p[100010];
ll s[400010],d1[400010],d2[400010],mx[400010],mn[400010];
//v‘=d1*v+d2
void gao(int x,ll len,ll f1,ll f2){
	d1[x]*=f1;
	d2[x]=d2[x]*f1+f2;
	s[x]=s[x]*f1+len*f2;
	mx[x]=mx[x]*f1+f2;
	mn[x]=mn[x]*f1+f2;
}
void pushdown(int x,int l,int r){
	int mid=(l+r)>>1;
	if(d1[x]!=1||d2[x]){
		gao(x<<1,mid-l+1,d1[x],d2[x]);
		gao(x<<1|1,r-mid,d1[x],d2[x]);
		d1[x]=1;
		d2[x]=0;
	}
}
ll min(ll a,ll b){return a<b?a:b;}
ll max(ll a,ll b){return a>b?a:b;}
void pushup(int x){
	s[x]=s[x<<1]+s[x<<1|1];
	mx[x]=max(mx[x<<1],mx[x<<1|1]);
	mn[x]=min(mn[x<<1],mn[x<<1|1]);
}
void modify(int L,int R,ll f1,ll f2,int l,int r,int x){
	if(L<=l&&r<=R)return gao(x,r-l+1,f1,f2);
	pushdown(x,l,r);
	int mid=(l+r)>>1;
	if(L<=mid)modify(L,R,f1,f2,l,mid,x<<1);
	if(mid<R)modify(L,R,f1,f2,mid+1,r,x<<1|1);
	pushup(x);
}
ll querysum(int L,int R,int l,int r,int x){
	if(L<=l&&r<=R)return s[x];
	pushdown(x,l,r);
	int mid=(l+r)>>1;
	ll ans=0;
	if(L<=mid)ans+=querysum(L,R,l,mid,x<<1);
	if(mid<R)ans+=querysum(L,R,mid+1,r,x<<1|1);
	return ans;
}
void sqrt(int L,int R,int l,int r,int x){
	if(L<=l&&r<=R&&mx[x]-mn[x]<=1){
		ll sqx,sqn;
		sqx=sqrt(mx[x]);
		sqn=sqrt(mn[x]);
		if(sqx==sqn)
			gao(x,r-l+1,0,sqx);
		else
			gao(x,r-l+1,1,sqx-mx[x]);
		return;
	}
	pushdown(x,l,r);
	int mid=(l+r)>>1;
	if(L<=mid)sqrt(L,R,l,mid,x<<1);
	if(mid<R)sqrt(L,R,mid+1,r,x<<1|1);
	pushup(x);
}
void build(int l,int r,int x){
	d1[x]=1;
	d2[x]=0;
	if(l==r){
		s[x]=mx[x]=mn[x]=p[l];
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,x<<1);
	build(mid+1,r,x<<1|1);
	pushup(x);
}
int main(){
	int t,n,m,i,op,l,r,x;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++)scanf("%d",p+i);
		build(1,n,1);
		while(m--){
			scanf("%d%d%d",&op,&l,&r);
			if(op==1){
				scanf("%d",&x);
				modify(l,r,1,x,1,n,1);
			}
			if(op==2)sqrt(l,r,1,n,1);
			if(op==3)printf("%lld\\n",querysum(l,r,1,n,1));
		}
	}
}

以上是关于[HDU5828]Rikka with Sequence的主要内容,如果未能解决你的问题,请参考以下文章

[HDU5828]Rikka with Sequence

HDU 5828 Rikka with Sequence

HDU 5634 Rikka with Phi

HDU 5634 Rikka with Phi

hdu 6090 Rikka with Graph

HDU 6095: Rikka with Competition