模板:吉司机线段树

所谓吉司机线段树,就是吉司机种的线段树

(逃)

解析

之前也看过一些相关内容的博客,但是因标记乱七八糟,感觉过于高深而放弃了…
直到看到洛谷这篇博客,完全颠覆了我的认知。(怎么感觉语气像营销号

原来是很小清新的算法,记录的标记虽然不少,但关键其实就在于记录懒标记历史最值这个操作上,而且思路很自然。

再次强推这篇博客!
在它的光辉下,一切更多的文字都是多余的。
我可不是在水文啊

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read() {
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
  while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}

const int N=5e5+100;
const int inf=1e9;

int n,m;

#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
struct tree{
  int siz,maxa,maxb,add1,add2,add3,add4,sec,cnt;
  ll sum;
}tr[N<<2];
inline void pushup(int k){
  tr[k].siz=tr[ls].siz+tr[rs].siz;
  tr[k].sum=tr[ls].sum+tr[rs].sum;
  tr[k].maxa=max(tr[ls].maxa,tr[rs].maxa);
  tr[k].maxb=max(tr[ls].maxb,tr[rs].maxb);
  tr[k].sec=max(tr[ls].sec,tr[rs].sec);
  if(tr[ls].maxa<tr[k].maxa) tr[k].sec=max(tr[k].sec,tr[ls].maxa);
  if(tr[rs].maxa<tr[k].maxa) tr[k].sec=max(tr[k].sec,tr[rs].maxa);
  tr[k].cnt=0;
  if(tr[k].maxa==tr[ls].maxa) tr[k].cnt+=tr[ls].cnt;
  if(tr[k].maxa==tr[rs].maxa) tr[k].cnt+=tr[rs].cnt;
  return;
}
inline void Add(int k,int add1,int add2,int add3,int add4){
  tr[k].sum+=1ll*tr[k].cnt*add1+1ll*(tr[k].siz-tr[k].cnt)*add2;
  tr[k].maxb=max(tr[k].maxb,tr[k].maxa+add3);
  tr[k].maxa+=add1;
  tr[k].add3=max(tr[k].add3,tr[k].add1+add3);
  tr[k].add4=max(tr[k].add4,tr[k].add2+add4);
  tr[k].add1+=add1;
  tr[k].add2+=add2;
  tr[k].sec+=add2;
  return;
}
inline void pushdown(int k){
  ll mx=max(tr[ls].maxa,tr[rs].maxa);
  if(mx==tr[ls].maxa) Add(ls,tr[k].add1,tr[k].add2,tr[k].add3,tr[k].add4);
  else Add(ls,tr[k].add2,tr[k].add2,tr[k].add4,tr[k].add4);
  
  if(mx==tr[rs].maxa) Add(rs,tr[k].add1,tr[k].add2,tr[k].add3,tr[k].add4);
  else Add(rs,tr[k].add2,tr[k].add2,tr[k].add4,tr[k].add4);
  tr[k].add1=tr[k].add2=tr[k].add3=tr[k].add4=0;
}
int a[N];
void build(int k,int l,int r){
  if(l==r){
    tr[k].siz=1;
    tr[k].maxa=tr[k].maxb=tr[k].sum=a[l];
    tr[k].cnt=1;
    tr[k].sec=-inf;
    tr[k].add1=tr[k].add2=tr[k].add3=tr[k].add4=0;
    return;
  }
  build(ls,l,mid);
  build(rs,mid+1,r);
  pushup(k);
  return;
}
void upd_add(int k,int l,int r,int x,int y,int w){
  if(x<=l&&r<=y){
    Add(k,w,w,w,w);return;
  }
  pushdown(k);
  if(x<=mid) upd_add(ls,l,mid,x,y,w);
  if(y>mid) upd_add(rs,mid+1,r,x,y,w);
  pushup(k);
}
void upd_min(int k,int l,int r,int x,int y,int w){
  if(tr[k].maxa<=w) return;
  if(x<=l&&r<=y&&tr[k].sec<w){
    Add(k,w-tr[k].maxa,0,w-tr[k].maxa,0);
    return;
  }
  pushdown(k);
  if(x<=mid) upd_min(ls,l,mid,x,y,w);
  if(y>mid) upd_min(rs,mid+1,r,x,y,w);
  pushup(k);
}
ll ask_sum(int k,int l,int r,int x,int y){
  if(x<=l&&r<=y) return tr[k].sum;
  ll res(0);
  pushdown(k);
  if(x<=mid) res+=ask_sum(ls,l,mid,x,y);
  if(y>mid) res+=ask_sum(rs,mid+1,r,x,y);
  return res;
}
ll ask_maxa(int k,int l,int r,int x,int y){
  if(x<=l&&r<=y) return tr[k].maxa;
  ll res=-inf;
  pushdown(k);
  if(x<=mid) res=max(res,ask_maxa(ls,l,mid,x,y));
  if(y>mid) res=max(res,ask_maxa(rs,mid+1,r,x,y));
  return res;
}
ll ask_maxb(int k,int l,int r,int x,int y){
  if(x<=l&&r<=y) return tr[k].maxb;
  ll res=-inf;
  pushdown(k);
  if(x<=mid) res=max(res,ask_maxb(ls,l,mid,x,y));
  if(y>mid) res=max(res,ask_maxb(rs,mid+1,r,x,y));
  return res;
}

signed main(){
   #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
  #endif
  n=read();m=read();
  for(int i=1;i<=n;i++) a[i]=read();
  build(1,1,n);
  for(int i=1;i<=m;i++){
    int op=read(),l=read(),r=read(),w;
    if(op<=2) w=read();
    if(op==1) upd_add(1,1,n,l,r,w);
    else if(op==2) upd_min(1,1,n,l,r,w);
    else if(op==3) printf("%lld\n",ask_sum(1,1,n,l,r));
    else if(op==4) printf("%lld\n",ask_maxa(1,1,n,l,r));
    else printf("%lld\n",ask_maxb(1,1,n,l,r));
  }
  return 0;
}
/*
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值