写在前面
ldx神犇今讲线段树,然后就涉及到了本题目的一个骚操作。
Solution
注意到本题实际上要求的是区间加,区间求和,区间开根号。前两个是常规操作,学了都会,然而怎样开根号?显然我们应该暴力修改对开方这个操作本身进行考虑。那么注意到,开一次方,一个序列中的每个数逐步接近其他的数,所以说我们可以考虑这么干:对序列维护一个最大值与最小值,如果说他们开方以后最大值减去最小值的差大于1,那么我们就认为这些数还不够接近,所以说直接递归修改这些区间,如果说这个差小于等于1,那么我们就继续暴力讨论一下。如果说这个差等于0,那么区间开方操作就相当于一次区间覆盖操作,这是常规操作,如果大于0小于等于1,那么可以看作一次区间减操作,这也很常规,那么这样我们就把题目分析完了。
#include<bits/stdc++.h>
using namespace std;
#define N 100010
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
typedef long long ll;
ll read(){
ll sum=0,neg=1;
char c=getchar();
while(c>'9'||c<'0'&&c!='-') c=getchar();
if(c=='-') neg=-1,c=getchar();
while(c>='0'&&c<='9') sum=(sum<<1)+(sum<<3)+c-'0',c=getchar();
return sum*neg;
}
ll n,m,T,a[N];
struct Node{
int l,r;
ll sum,minn,maxn,lazy,tag;
};
struct SegmentTree{
Node T[N*4];
void pushup(int p){
T[p].maxn=max(T[lc].maxn,T[rc].maxn);
T[p].minn=min(T[lc].minn,T[rc].minn);
T[p].sum=T[lc].sum+T[rc].sum;
}
void pushnow(int p,ll v){
T[p].sum+=(T[p].r-T[p].l+1)*v;
T[p].lazy+=v;
T[p].maxn+=v;
T[p].minn+=v;
}
void pushcover(int p,ll v){
T[p].lazy=0;
T[p].sum=(T[p].r-T[p].l+1)*v;
T[p].tag=T[p].maxn=T[p].minn=v;
}
void pushdown(int p){
if(T[p].tag!=-1){
pushcover(lc,T[p].tag);
pushcover(rc,T[p].tag);
T[p].tag=-1;
}
if(T[p].lazy){
pushnow(lc,T[p].lazy);
pushnow(rc,T[p].lazy);
T[p].lazy=0;
}
}
void build(int p,int l,int r){
T[p].l=l; T[p].r=r; T[p].lazy=0; T[p].tag=-1;
if(l==r){
T[p].maxn=T[p].minn=T[p].sum=a[l];
return;
}
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p);
}
void update(int p,int ql,int qr,ll v){
if(ql>T[p].r||qr<T[p].l) return;
if(ql<=T[p].l&&T[p].r<=qr){
pushnow(p,v);
return;
}
pushdown(p);
if(qr<=mid) update(lc,ql,qr,v);
else if(ql>mid) update(rc,ql,qr,v);
else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
pushup(p);
}
void modify(int p,int ql,int qr){
if(ql>T[p].r||qr<T[p].l) return;
if(ql<=T[p].l&&T[p].r<=qr&&T[p].maxn-T[p].minn<=1){
ll fx=sqrt(T[p].maxn),fy=sqrt(T[p].minn);
if(fx==fy) pushcover(p,fx);
else pushnow(p,fx-T[p].maxn);
return;
}
pushdown(p);
if(qr<=mid)modify(lc,ql,qr);
else if(ql>mid)modify(rc,ql,qr);
else modify(lc,ql,mid),modify(rc,mid+1,qr);
pushup(p);
}
ll query(int p,int ql,int qr){
if(ql>T[p].r||qr<T[p].l) return 0;
if(ql<=T[p].l&&T[p].r<=qr) return T[p].sum;
pushdown(p);
if(qr<=mid) return query(lc,ql,qr);
if(ql>mid) return query(rc,ql,qr);
return query(lc,ql,mid)+query(rc,mid+1,qr);
}
}Tree;
int main(){
T=read();
while(T--){
n=read(); m=read();
for(int i=1;i<=n;i++) a[i]=read();
Tree.build(1,1,n);
while(m--){
int opt,l,r;
opt=read(); l=read(); r=read();
switch(opt){
case 1:{
ll v=read();
Tree.update(1,l,r,v);
break;
}
case 2:{
Tree.modify(1,l,r);
break;
}
default:{
printf("%lld\n",Tree.query(1,l,r));
break;
}
}
}
}
return 0;
}