uoj#228. 基礎數據結構練習題

第一次看到這題大概在這裏:2016多校聯合

反正當時也沒什麼想法,表示有區間加好難受。

題解並不難,維護每個區間最值、和,當一個區間開根後所有值都一樣就直接賦值,否則遞歸。存在一種特例:3 4 3 4 3 4 3 4 3,開根後1 2 1 2 1 2 1 2 1.,+2: 3 4 3 4 3 4 3 4 3,,成功卡到暴力,所以要特判,原因大概是取整吧。

所以就有了:


後來發現ad忘記賦0。。。

#include<iostream>
#include<cstdio>
#include<cmath>
#define N 100005
#define ll long long
using namespace std;
ll n,m,a[N],Mx[N<<2],Mn[N<<2],Sm[N<<2],fl[N<<2],ad[N<<2];
void dn(ll k,ll l,ll r)
{
	ll mid=l+r>>1;
	if (fl[k])
	{
		fl[k<<1]=Mx[k<<1]=Mn[k<<1]=fl[k];Sm[k<<1]=fl[k]*(mid-l+1);ad[k<<1]=0;
		fl[k<<1|1]=Mx[k<<1|1]=Mn[k<<1|1]=fl[k];Sm[k<<1|1]=fl[k]*(r-mid);ad[k<<1|1]=0;
		fl[k]=0;
	}
	if (ad[k])
	{
		ad[k<<1]+=ad[k];Mx[k<<1]+=ad[k];Mn[k<<1]+=ad[k];Sm[k<<1]+=ad[k]*(mid-l+1);
		ad[k<<1|1]+=ad[k];Mx[k<<1|1]+=ad[k];Mn[k<<1|1]+=ad[k];Sm[k<<1|1]+=ad[k]*(r-mid);
		ad[k]=0;
	}
}
void up(ll k)
{
	Mx[k]=max(Mx[k<<1],Mx[k<<1|1]);
	Mn[k]=min(Mn[k<<1],Mn[k<<1|1]);
	Sm[k]=Sm[k<<1]+Sm[k<<1|1];
}
void build(ll k,ll l,ll r)
{
	fl[k]=ad[k]=0;
	if (l==r)
	{
		Mx[k]=Mn[k]=Sm[k]=a[l];
		return;
	}
	ll mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	up(k);
}
void add(ll k,ll l,ll r,ll x,ll y,ll z)
{
	if (x<=l&&r<=y)
	{
		Mx[k]+=z;Mn[k]+=z;Sm[k]+=z*(r-l+1);ad[k]+=z;
		return;
	}
	ll mid=l+r>>1;
	dn(k,l,r);
	if (x<=mid) add(k<<1,l,mid,x,y,z);
	if (y>mid) add(k<<1|1,mid+1,r,x,y,z);
	up(k);
}
void mdy(ll k,ll l,ll r,ll x,ll y)
{
	if (x<=l&&r<=y)
	{
		ll t=sqrt(Mx[k]);
		if (t==(ll)sqrt(Mn[k]))
		{
			Mx[k]=t;Mn[k]=t;Sm[k]=t*(r-l+1);fl[k]=t;ad[k]=0;
			return;
		}
		if (Mx[k]==Mn[k]+1&&t*t==Mx[k])
		{
		
			Mx[k]-=t*(t-1);Mn[k]-=t*(t-1);Sm[k]-=t*(t-1)*(r-l+1);ad[k]-=t*(t-1);
			return;
		}
	}
	ll mid=l+r>>1;
	dn(k,l,r);
	if (x<=mid) mdy(k<<1,l,mid,x,y);
	if (y>mid) mdy(k<<1|1,mid+1,r,x,y);
	up(k);
}
ll qry(ll k,ll l,ll r,ll x,ll y)
{
	if (x<=l&&r<=y) return Sm[k];
	ll mid=l+r>>1,Ans=0;
	dn(k,l,r);
	if (x<=mid) Ans=qry(k<<1,l,mid,x,y);
	if (y>mid) Ans+=qry(k<<1|1,mid+1,r,x,y);
	return Ans;
}
int main()
{
		
	scanf("%lld%lld",&n,&m);
	
	for (ll i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	build(1,1,n);
	for (ll i=1;i<=m;i++)
	{
		ll p,x,y,z;
		scanf("%lld%lld%lld",&p,&x,&y);
		if (p==1)
		{
			scanf("%lld",&z);
			add(1,1,n,x,y,z);
		}
		if (p==2) mdy(1,1,n,x,y);
		if (p==3) printf("%lld\n",qry(1,1,n,x,y));
	}
	
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章