【UOJ228基础数据结构练习题】
==看到开根 第一反应之前那个区间开根 每个数最多只会开5次
可是这题又有加法操作 如果这次开完 下一次又加回来不断循环就爆炸了
如果一段区间的数开方后减少的值相同 我们就可以转化为区间减法 这样复杂度就可以保证了==
比如8 9
开方后是2 3
减少的值都为6
所以线段树还要再维护区间最大和最小 每次开方时特判其减少的值是否相等
yyb大佬的总结
这类题目的重点在于这些特殊操作的处理
此时的思考的主要方向已经不是线段树如何使用了
而是想清楚当前操作具有的特殊性质
再来相应地在线段树上维护所需要的东西
#include
using namespace std;
#define ll long long
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
#define ls (o<<1)
#define rs (o<<1|1)
const int N=1e5+5,M=32000+5,inf=0x3f3f3f3f;
int n,m,a[N],b[N];
template void rd(t &x){
x=0;int w=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=w?-x:x;
}
struct node{ll mx,mn,add,sum;}t[N<<2];
void pup(int o){
t[o].sum=t[ls].sum+t[rs].sum;
t[o].mx=Max(t[ls].mx,t[rs].mx);
t[o].mn=Min(t[ls].mn,t[rs].mn);
}
void updnode(int o,int l,int r,ll k){
t[o].sum+=(ll)(r-l+1)*k;
t[o].add+=k,t[o].mn+=k,t[o].mx+=k;
}
void pudw(int o,int l,int r){
int mid=l+r>>1;
if(t[o].add!=0) updnode(ls,l,mid,t[o].add),updnode(rs,mid+1,r,t[o].add),t[o].add=0;
}
void upd1(int o,int l,int r,int x,int y,ll k){
if(l>y||r>1;
upd1(ls,l,mid,x,y,k),upd1(rs,mid+1,r,x,y,k);
pup(o);
}
void upd2(int o,int l,int r,int x,int y){
if(l>y||r>1;
upd2(ls,l,mid,x,y),upd2(rs,mid+1,r,x,y);
pup(o);
}
ll query(int o,int l,int r,int x,int y){
if(l>y||r>1;ll ans=0ll;
ans+=query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
pup(o);
return ans;
}
void build(int o,int l,int r){
t[o].add=0;
if(l==r){t[o].mn=t[o].mx=t[o].sum=a[l];return;}
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
pup(o);
}
int main(){
freopen("in.txt","r",stdin);
// freopen("numbers.out","w",stdout);
rd(n),rd(m);
for(int i=1;i<=n;++i) rd(a[i]);
build(1,1,n);
for(int i=1,opt,x,y,k;i<=m;++i){
rd(opt),rd(x),rd(y);
if(opt==1)
rd(k),upd1(1,1,n,x,y,k);
else if(opt==2) upd2(1,1,n,x,y);
else printf("%lld\n",query(1,1,n,x,y));
}
return 0;
}