写在前面
ldx神犇今讲线段树,然后就涉及到了本题目的一个骚操作。
传送门
Solution
注意到本题实际上要求的是区间加,区间求和,区间开根号。前两个是常规操作,学了都会,然而怎样开根号?显然我们应该暴力修改开方这个操作本身进行考虑。那么注意到,开一次方,一个序列中的每个数逐步接近其他的数,所以说我们可以考虑这么干:对序列维护一个最大值与最小值,如果说他们开方以后最大值减去最小值的差大于1,那么我们就认为这些数还不够接近,所以说直接递归修改这些区间,如果说这个差小于等于1,那么我们就继续暴力讨论一下。如果说这个差等于0,那么区间开方操作就相当于一次区间覆盖操作,这是常规操作,如果大于0小于等于1,那么可以看作一次区间减操作,这也很常规,那么这样我们就把题目分析完了。
代码如下
1 #include2 using namespace std; 3 #define N 100010 4 #define lc (p<<1) 5 #define rc (p<<1|1) 6 #define mid (T[p].l+T[p].r>>1) 7 typedef long long ll; 8 ll read(){ 9 ll sum=0,neg=1; 10 char c=getchar(); 11 while(c>'9'||c<'0'&&c!='-') c=getchar(); 12 if(c=='-') neg=-1,c=getchar(); 13 while(c>='0'&&c<='9') sum=(sum<<1)+(sum<<3)+c-'0',c=getchar(); 14 return sum*neg; 15 } 16 ll n,m,T,a[N]; 17 struct Node{ 18 int l,r; 19 ll sum,minn,maxn,lazy,tag; 20 }; 21 struct SegmentTree{ 22 Node T[N*4]; 23 void pushup(int p){ 24 T[p].maxn=max(T[lc].maxn,T[rc].maxn); 25 T[p].minn=min(T[lc].minn,T[rc].minn); 26 T[p].sum=T[lc].sum+T[rc].sum; 27 } 28 void pushnow(int p,ll v){ 29 T[p].sum+=(T[p].r-T[p].l+1)*v; 30 T[p].lazy+=v; 31 T[p].maxn+=v; 32 T[p].minn+=v; 33 } 34 void pushcover(int p,ll v){ 35 T[p].lazy=0; 36 T[p].sum=(T[p].r-T[p].l+1)*v; 37 T[p].tag=T[p].maxn=T[p].minn=v; 38 } 39 void pushdown(int p){ 40 if(T[p].tag!=-1){ 41 pushcover(lc,T[p].tag); 42 pushcover(rc,T[p].tag); 43 T[p].tag=-1; 44 } 45 if(T[p].lazy){ 46 pushnow(lc,T[p].lazy); 47 pushnow(rc,T[p].lazy); 48 T[p].lazy=0; 49 } 50 } 51 void build(int p,int l,int r){ 52 T[p].l=l; T[p].r=r; T[p].lazy=0; T[p].tag=-1; 53 if(l==r){ 54 T[p].maxn=T[p].minn=T[p].sum=a[l]; 55 return; 56 } 57 build(lc,l,mid); 58 build(rc,mid+1,r); 59 pushup(p); 60 } 61 void update(int p,int ql,int qr,ll v){ 62 if(ql>T[p].r||qr return; 63 if(ql<=T[p].l&&T[p].r<=qr){ 64 pushnow(p,v); 65 return; 66 } 67 pushdown(p); 68 if(qr<=mid) update(lc,ql,qr,v); 69 else if(ql>mid) update(rc,ql,qr,v); 70 else update(lc,ql,mid,v),update(rc,mid+1,qr,v); 71 pushup(p); 72 } 73 void modify(int p,int ql,int qr){ 74 if(ql>T[p].r||qr return; 75 if(ql<=T[p].l&&T[p].r<=qr&&T[p].maxn-T[p].minn<=1){ 76 ll fx=sqrt(T[p].maxn),fy=sqrt(T[p].minn); 77 if(fx==fy) pushcover(p,fx); 78 else pushnow(p,fx-T[p].maxn); 79 return; 80 } 81 pushdown(p); 82 if(qr<=mid)modify(lc,ql,qr); 83 else if(ql>mid)modify(rc,ql,qr); 84 else modify(lc,ql,mid),modify(rc,mid+1,qr); 85 pushup(p); 86 } 87 ll query(int p,int ql,int qr){ 88 if(ql>T[p].r||qr return 0; 89 if(ql<=T[p].l&&T[p].r<=qr) return T[p].sum; 90 pushdown(p); 91 if(qr<=mid) return query(lc,ql,qr); 92 if(ql>mid) return query(rc,ql,qr); 93 return query(lc,ql,mid)+query(rc,mid+1,qr); 94 } 95 }Tree; 96 int main(){ 97 T=read(); 98 while(T--){ 99 n=read(); m=read(); 100 for(int i=1;i<=n;i++) a[i]=read(); 101 Tree.build(1,1,n); 102 while(m--){ 103 int opt,l,r; 104 opt=read(); l=read(); r=read(); 105 switch(opt){ 106 case 1:{ 107 ll v=read(); 108 Tree.update(1,l,r,v); 109 break; 110 } 111 case 2:{ 112 Tree.modify(1,l,r); 113 break; 114 } 115 default:{ 116 printf("%lld\n",Tree.query(1,l,r)); 117 break; 118 } 119 } 120 } 121 } 122 return 0; 123 }