【题意】给了一个序列,3个操作,1是给区间[l,r]加上一个数,2是给区间[l,r]里每个数开平方,3是查询[l,r]的和。
【解题方法】
其实这道题线段树就完全可以维护了,平衡树不会,线段树节点里面保存了两个标记,一个是add(区间加),一个是区间里面元素是否相同,接下来很重要的主要是pushdown的写法了,这里一定要先考虑issame标记,然后考虑add,这个顺序一定不能反。具体细节见代码了。
【AC 代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e5+10;
struct node{
int l,r;
LL sum;
LL add,issame;
}Tree[maxn<<2];
void pushup(int rt){
if(Tree[rt*2].issame&&Tree[rt*2+1].issame&&Tree[rt*2].issame==Tree[rt*2+1].issame){
Tree[rt].issame=Tree[rt*2].issame;
}else{
Tree[rt].issame=0;
}
Tree[rt].sum=Tree[rt*2].sum+Tree[rt*2+1].sum;
}
void pushdown(int rt){
int m=(Tree[rt].r+Tree[rt].l)/2;
if(Tree[rt].issame){
Tree[rt*2].issame=Tree[rt].issame;
Tree[rt*2+1].issame=Tree[rt].issame;
Tree[rt*2].sum=(m-Tree[rt].l+1)*Tree[rt].issame;
Tree[rt*2+1].sum=(Tree[rt].r-m)*(Tree[rt].issame);
}else{
Tree[rt*2].add+=Tree[rt].add;
Tree[rt*2+1].add+=Tree[rt].add;
Tree[rt*2].sum+=Tree[rt].add*(m-Tree[rt].l+1);
Tree[rt*2+1].sum+=Tree[rt].add*(Tree[rt].r-m);
Tree[rt].add=0;
if(Tree[rt*2].issame){
Tree[rt*2].issame+=Tree[rt*2].add;
Tree[rt*2].add=0;
}
if(Tree[rt*2+1].issame){
Tree[rt*2+1].issame+=Tree[rt*2+1].add;
Tree[rt*2+1].add=0;
}
}
}
int A[maxn];
void Build(int l,int r,int rt){
Tree[rt].l=l,Tree[rt].r=r;
Tree[rt].add=0;
if(l==r){
Tree[rt].sum=A[l];
Tree[rt].issame=A[l];
return ;
}
int mid=(l+r)/2;
Build(l,mid,rt*2);
Build(mid+1,r,rt*2+1);
pushup(rt);
}
void update1(int L,int R,LL v,int rt){
if(L==Tree[rt].l&&Tree[rt].r==R){
Tree[rt].sum+=v*(Tree[rt].r-Tree[rt].l+1);
if(Tree[rt].issame){
Tree[rt].issame+=v;
}else{
Tree[rt].add+=v;
}
return ;
}
pushdown(rt);
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(R<=mid) update1(L,R,v,rt*2);
else if(L>mid) update1(L,R,v,rt*2+1);
else{
update1(L,mid,v,rt*2);
update1(mid+1,R,v,rt*2+1);
}
pushup(rt);
}
void update2(int L,int R,int rt){
if(L==Tree[rt].l&&R==Tree[rt].r&&Tree[rt].issame){
Tree[rt].issame=sqrt(Tree[rt].issame);
Tree[rt].sum=Tree[rt].issame*(Tree[rt].r-Tree[rt].l+1);
return ;
}
pushdown(rt);
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(R<=mid) update2(L,R,rt*2);
else if(L>mid) update2(L,R,rt*2+1);
else{
update2(L,mid,rt*2);
update2(mid+1,R,rt*2+1);
}
pushup(rt);
}
LL queryans(int L,int R,int rt){
if(L==Tree[rt].l&&R==Tree[rt].r){
return Tree[rt].sum;
}
pushdown(rt);
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(R<=mid) return queryans(L,R,rt*2);
else if(L>mid) return queryans(L,R,rt*2+1);
else{
return queryans(L,mid,rt*2)+queryans(mid+1,R,rt*2+1);
}
}
int main(){
int T,n,m;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++){
scanf("%d",&A[i]);
}
Build(1,n,1);
//puts("success");
int op,l,r;LL x;
for(int i=1; i<=m; i++){
scanf("%d",&op);
if(op==1){
scanf("%d%d%lld",&l,&r,&x);
update1(l,r,x,1);
}else if(op==2){
scanf("%d%d",&l,&r);
update2(l,r,1);
}
else{
scanf("%d%d",&l,&r);
LL ans=queryans(l,r,1);
printf("%lld\n",ans);
}
}
}
return 0;
}