第一次看到這題大概在這裏: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;
}