[线段树 区间最值操作 模板 Segment tree Beats!] BZOJ 4695 最假女选手

鬼畜线段树的大模板题 具体见吉丽的集训队论文
我终于会写线段树了 不对 我好像还不会历史最值

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=500005;
const int M=N<<2;

int mx[M],sx[M],cx[M],mn[M],sn[M],cn[M]; ll sum[M]; int ta[M];

inline void update(int x){
  int l=x<<1,r=x<<1|1;
  sum[x]=sum[l]+sum[r];
  if (mx[l]==mx[r])
    mx[x]=mx[l],cx[x]=cx[l]+cx[r],sx[x]=max(sx[l],sx[r]);
  else{ // r>l
    if (mx[l]>mx[r]) swap(l,r);
    mx[x]=mx[r]; cx[x]=cx[r];
    sx[x]=max(sx[r],mx[l]);
  }
  if (mn[l]==mn[r])
    mn[x]=mn[l],cn[x]=cn[l]+cn[r],sn[x]=min(sn[l],sn[r]);
  else{ // r<l
    if (mn[l]<mn[r]) swap(l,r);
    mn[x]=mn[r]; cn[x]=cn[r];
    sn[x]=min(sn[r],mn[l]);
  }
}

inline void Build(int x,int l,int r){
  if (l==r){
    int a; read(a);
    sum[x]=mx[x]=mn[x]=a; cx[x]=cn[x]=1; sx[x]=-1<<30; sn[x]=1<<30; ta[x]=0;
    return;
  }
  int mid=(l+r)>>1; Build(x<<1,l,mid); Build(x<<1|1,mid+1,r);
  update(x);
}

inline void _add(int x,int l,int r,int t){
  sum[x]+=(ll)(r-l+1)*t;
  mn[x]+=t; sn[x]+=t; mx[x]+=t; sx[x]+=t;
  ta[x]+=t;
}
inline void _min(int x,int l,int r,int t){
  sum[x]-=(ll)cx[x]*(mx[x]-t);
  mx[x]=t; mn[x]=min(mn[x],t);
  if (mn[x]==mx[x]){
    sum[x]=(ll)(r-l+1)*t; cx[x]=cn[x]=r-l+1; sx[x]=-1<<30; sn[x]=1<<30;
  }else
    sn[x]=min(sn[x],t);
}
inline void _max(int x,int l,int r,int t){
  sum[x]+=(ll)cn[x]*(t-mn[x]);
  mn[x]=t; mx[x]=max(mx[x],t);
  if (mn[x]==mx[x]){
    sum[x]=(ll)(r-l+1)*t; cx[x]=cn[x]=r-l+1; sx[x]=-1<<30; sn[x]=1<<30;
  }else
    sx[x]=max(sx[x],t);
}
inline void push(int x,int l,int r){
  int mid=(l+r)>>1;
  if (ta[x]){
    _add(x<<1,l,mid,ta[x]);
    _add(x<<1|1,mid+1,r,ta[x]);
    ta[x]=0;
  }
  if (mx[x<<1]>mx[x] && sx[x<<1]<mx[x]) _min(x<<1,l,mid,mx[x]);
  if (mx[x<<1|1]>mx[x] && sx[x<<1|1]<mx[x]) _min(x<<1|1,mid+1,r,mx[x]);
  if (mn[x<<1]<mn[x] && sn[x<<1]>mn[x]) _max(x<<1,l,mid,mn[x]);
  if (mn[x<<1|1]<mn[x] && sn[x<<1|1]>mn[x]) _max(x<<1|1,mid+1,r,mn[x]);
}

int ql,qr,qt;

inline void Mmax(int x,int l,int r){
  if (mn[x]>=qt) return;
  if (ql<=l && r<=qr && qt<sn[x]){
    _max(x,l,r,qt); return;
  }
  push(x,l,r); int mid=(l+r)>>1;
  if (ql<=mid) Mmax(x<<1,l,mid);
  if (qr>mid) Mmax(x<<1|1,mid+1,r);
  update(x);
}
inline void Mmin(int x,int l,int r){
  if (mx[x]<=qt) return;
  if (ql<=l && r<=qr && qt>sx[x]){
    _min(x,l,r,qt); return;
  }
  push(x,l,r); int mid=(l+r)>>1;
  if (ql<=mid) Mmin(x<<1,l,mid);
  if (qr>mid) Mmin(x<<1|1,mid+1,r);
  update(x);
}
inline void Add(int x,int l,int r){
  if (ql<=l && r<=qr){
    _add(x,l,r,qt); return;
  }
  push(x,l,r); int mid=(l+r)>>1;
  if (ql<=mid) Add(x<<1,l,mid);
  if (qr>mid) Add(x<<1|1,mid+1,r);
  update(x);
}

inline int Max(int x,int l,int r){
  if (ql<=l && r<=qr) return mx[x];
  push(x,l,r);
  int ret=-1<<30; int mid=(l+r)>>1;
  if (ql<=mid) ret=max(ret,Max(x<<1,l,mid));
  if (qr>mid) ret=max(ret,Max(x<<1|1,mid+1,r));
  return ret;
}
inline int Min(int x,int l,int r){
  if (ql<=l && r<=qr) return mn[x];
  push(x,l,r);
  int ret=1<<30; int mid=(l+r)>>1;
  if (ql<=mid) ret=min(ret,Min(x<<1,l,mid));
  if (qr>mid) ret=min(ret,Min(x<<1|1,mid+1,r));
  return ret;
}
inline ll Sum(int x,int l,int r){
  if (ql<=l && r<=qr) return sum[x];
  push(x,l,r);
  ll ret=0; int mid=(l+r)>>1;
  if (ql<=mid) ret+=Sum(x<<1,l,mid);
  if (qr>mid) ret+=Sum(x<<1|1,mid+1,r);
  return ret;
}

int n;

int main(){
  int Q,order,t;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); Build(1,1,n);
  read(Q);
  while (Q--){
    read(order); read(ql); read(qr);
    if (order==1){
      read(qt),Add(1,1,n);
    }else if (order==2){
      read(qt),Mmax(1,1,n);
    }else if (order==3){
      read(qt),Mmin(1,1,n);
    }else if (order==4){
      printf("%lld\n",Sum(1,1,n));
    }else if (order==5){
      printf("%d\n",Max(1,1,n));
    }else if (order==6){
      printf("%d\n",Min(1,1,n));
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值