题目链接:
C-势能线段树模板题二_牛客竞赛数据结构专题班势能线段树、李超线段树 (nowcoder.com)
题意:
样例:
输入
10 3
10 10 10 10 10 10 10 10 10 10
1 1 5
2 1 10 5
3 1 10
输出
115
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
typedef struct Node{
int l,r;
ll sum;
ll ma,mi,lazy,set;
}Node;
Node tr[N*4];
int a[N];
int n,m;
void init_lazy(int u){
tr[u].lazy=tr[u].set=0;
}
void cal_lazy1(int u,ll k){
int len=tr[u].r-tr[u].l+1;
tr[u].sum+=len*k;
tr[u].lazy+=k;
tr[u].ma=tr[u].ma+k;
tr[u].mi=tr[u].mi+k;
}
void cal_lazy2(int u){
ll tmp=sqrt(tr[u].ma+0.5);
tr[u].set=1;
tr[u].ma=tr[u].mi=tmp;
int len=tr[u].r-tr[u].l+1;
tr[u].sum=len*tmp;
}
void pushup(int u){
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
tr[u].ma=max(tr[u<<1].ma,tr[u<<1|1].ma);
tr[u].mi=min(tr[u<<1].mi,tr[u<<1|1].mi);
}
void build(int u,int l,int r){
tr[u].l=l,tr[u].r=r;
init_lazy(u);
if(l==r){
tr[u].sum=tr[u].ma=tr[u].mi=a[l];
}
else{
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
void tag_union(int fa,int ch){
if(tr[fa].set!=0){
tr[ch].set=1;
tr[ch].ma=tr[ch].mi=tr[fa].ma;
int len=tr[ch].r-tr[ch].l+1;
tr[ch].sum=len*tr[ch].ma;
tr[ch].lazy=0;
}
else{
ll k=tr[fa].lazy;
int len=tr[ch].r-tr[ch].l+1;
tr[ch].lazy+=k;
tr[ch].ma=tr[ch].ma+k;
tr[ch].mi=tr[ch].mi+k;
tr[ch].sum+=len*k;
}
}
void pushdown(int u){
if(tr[u].lazy || tr[u].set){
if(tr[u].l!=tr[u].r){
tag_union(u,u<<1);
tag_union(u,u<<1|1);
}
init_lazy(u);
}
}
ll query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r)
return tr[u].sum;
pushdown(u);
int mid=(tr[u].l+tr[u].r)>>1;
ll res=0;
if(l<=mid)
res+=query(u<<1,l,r);
if(r>mid)
res+=query(u<<1|1,l,r);
return res;
}
void add(int u,int l,int r,ll k){
if(tr[u].l>=l&&tr[u].r<=r){
cal_lazy1(u,k);
return;
}
pushdown(u);
int mid=(tr[u].l+tr[u].r)>>1;
if(l<=mid)
add(u<<1,l,r,k);
if(r>mid)
add(u<<1|1,l,r,k);
pushup(u);
}
void do_sqrt(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
if(tr[u].ma==tr[u].mi){
cal_lazy2(u);
return;
}
pushdown(u);
int mid=(tr[u].l+tr[u].r)>>1;
do_sqrt(u<<1,l,r);
do_sqrt(u<<1|1,l,r);
pushup(u);
return;
}
pushdown(u);
int mid=(tr[u].l+tr[u].r)>>1;
if(l<=mid)
do_sqrt(u<<1,l,r);
if(r>mid)
do_sqrt(u<<1|1,l,r);
pushup(u);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
int op,l,r,x;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&op,&l,&r);
if(op==1){
do_sqrt(1,l,r);
}
else if(op==2){
scanf("%d",&x);
add(1,l,r,x);
}
else{
printf("%lld\n",query(1,l,r));
}
}
}