BZOJ 4695 最假女选手 线段树

时间:2021-08-29 18:55:03

题意:

  给定一个长度为 N序列,编号从1 到 N。要求支持下面几种操作:

  1.给一个区间[L,R] 加上一个数x 
  2.把一个区间[L,R] 里小于x 的数变成x 
  3.把一个区间[L,R] 里大于x 的数变成x 
  4.求区间[L,R] 的和
  5.求区间[L,R] 的最大值
  6.求区间[L,R] 的最小值
 

分析:

  你听说过Segment Tree Beats么?

  快去看一看吧。这题居然才只有六个操作,真的是重口难调啊。

  思想还是不难的,这里就不粘课件了。

  由于这题拥有着比较玄学的空间限制和比较玄学的数据范围,所以可能需要试探很多遍才能不MLE。

  (如果你是指针线段树我也没啥可说的)

  代码是我修改抄袭一位大神的,予以美化(好像更难读了),以便于非指针用户食用。

代码:

 #include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3.7e5+,inf=1e9;
struct node{
int l,r,ls,rs,mnc,mxc;//标号为1代表最值
ll mn1,mn2,mx1,mx2;//,为2代表次值
ll lmn,lmx,lad,s;//c代表的是count数量,不是次
}t[N<<];int cnt=,rt,n,m,x;
char readchar(){
static char buf[],*l=buf,*r=buf;
if(l==r) r=(l=buf)+fread(buf,,,stdin);
if(l==r) return EOF;return *l++;}
int read(){
int x=,f=;char ch=readchar();
while(ch<''||ch>''){if(ch=='-') f=-f;ch=readchar();}
while(ch<=''&&ch>=''){x=(x<<)+(x<<)+ch-'';ch=readchar();};
return x*f;
} void pushup(int cur){
int ls=t[cur].ls,rs=t[cur].rs;
t[cur].s=t[ls].s+t[rs].s;
if(t[ls].mn1<t[rs].mn1)
t[cur].mn1=t[ls].mn1,
t[cur].mnc=t[ls].mnc,
t[cur].mn2=min(t[ls].mn2,t[rs].mn1);
else if(t[ls].mn1>t[rs].mn1)
t[cur].mn1=t[rs].mn1,
t[cur].mnc=t[rs].mnc,
t[cur].mn2=min(t[rs].mn2,t[ls].mn1);
else t[cur].mn1=t[ls].mn1,
t[cur].mnc=t[ls].mnc+t[rs].mnc,
t[cur].mn2=min(t[ls].mn2,t[rs].mn2);
if(t[ls].mx1>t[rs].mx1)
t[cur].mx1=t[ls].mx1,
t[cur].mxc=t[ls].mxc,
t[cur].mx2=max(t[ls].mx2,t[rs].mx1);
else if(t[ls].mx1<t[rs].mx1)
t[cur].mx1=t[rs].mx1,
t[cur].mxc=t[rs].mxc,
t[cur].mx2=max(t[rs].mx2,t[ls].mx1);
else t[cur].mx1=t[ls].mx1,
t[cur].mxc=t[ls].mxc+t[rs].mxc,
t[cur].mx2=max(t[ls].mx2,t[rs].mx2);
} void adsm(int cur,ll x){
t[cur].mn1+=x;t[cur].mx1+=x;
if(t[cur].mn2!= inf) t[cur].mn2+=x;
if(t[cur].mx2!=-inf) t[cur].mx2+=x;
t[cur].s+=x*(t[cur].r-t[cur].l+);
t[cur].lad+=x;return ;
} void admn(int cur,ll x){
if(t[cur].mn1==t[cur].mx1) t[cur].mx1+=x;
if(t[cur].mn1==t[cur].mx2) t[cur].mx2+=x;
t[cur].lmn+=x;t[cur].mn1+=x;
t[cur].s+=x*t[cur].mnc;return ;
} void admx(int cur,ll x){
if(t[cur].mn1==t[cur].mx1) t[cur].mn1+=x;
if(t[cur].mx1==t[cur].mn2) t[cur].mn2+=x;
t[cur].mx1+=x;t[cur].lmx+=x;
t[cur].s+=x*t[cur].mxc;return ;
} void pushdown(int cur){
int ls=t[cur].ls,rs=t[cur].rs;
if(t[cur].lad) adsm(ls,t[cur].lad),
adsm(rs,t[cur].lad),t[cur].lad=;
if(t[cur].lmn){
if(t[ls].mn1<=t[rs].mn1)
admn(ls,t[cur].lmn);
if(t[ls].mn1>=t[rs].mn1)
admn(rs,t[cur].lmn);t[cur].lmn=;
} if(t[cur].lmx){
if(t[ls].mx1>=t[rs].mx1)
admx(ls,t[cur].lmx);
if(t[ls].mx1<=t[rs].mx1)
admx(rs,t[cur].lmx);t[cur].lmx=;
} return ;
} void build(int l,int r,int cur){
t[cur].l=l,t[cur].r=r;
if(l==r){ t[cur].mxc=;
t[cur].ls=t[cur].rs=-;t[cur].mnc=;
t[cur].lmn=t[cur].lmx=t[cur].lad=;
t[cur].s=t[cur].mx1=t[cur].mn1=read();
t[cur].mn2=inf;t[cur].mx2=-inf;return ;
} int mid=l+r>>;
t[cur].ls=cnt++;t[cur].rs=cnt++;
build(l,mid,t[cur].ls);
build(mid+,r,t[cur].rs);
pushup(cur);return ;
}
#define sum(x,y) x+y;
#define upd(fun,lm,req,tag) \
void fun(int l,int r,int cur){ \
if(lm) return ; \
if(l<=t[cur].l&&t[cur].r<=r&&req) \
{tag;return ;} pushdown(cur); \
int mid=t[cur].l+t[cur].r>>; \
if(l<=mid) fun(l,r,t[cur].ls); \
if(mid<r) fun(l,r,t[cur].rs); \
pushup(cur);return ; \
}
#define qry(fun,typ,ret,op) \
typ fun(int l,int r,int cur){ \
int ls=t[cur].ls,rs=t[cur].rs; \
if(l<=t[cur].l&&t[cur].r<=r) return ret;\
pushdown(cur); \
int mid=t[cur].l+t[cur].r>>; \
if(r<=mid) return fun(l,r,ls); \
if(mid<l) return fun(l,r,rs); \
return op(fun(l,r,ls),fun(l,r,rs)); \
}
upd(uad,,,adsm(cur,x))
upd(umn,t[cur].mn1>=x,t[cur].mn2>x,
admn(cur,x-t[cur].mn1))
upd(umx,t[cur].mx1<=x,t[cur].mx2<x,
admx(cur,x-t[cur].mx1))
qry(qsm,ll,t[cur].s,sum)
qry(qmx,ll,t[cur].mx1,max)
qry(qmn,ll,t[cur].mn1,min)
signed main(){
rt=cnt++;n=read();
build(,n,rt);m=read();
for(int l,r,op;m--;){
op=read();l=read();r=read();
if(op<=) x=read();
if(op==) uad(l,r,rt);
if(op==) umn(l,r,rt);
if(op==) umx(l,r,rt);
if(op==) printf("%lld\n",qsm(l,r,rt));
if(op==) printf("%lld\n",qmx(l,r,rt));
if(op==) printf("%lld\n",qmn(l,r,rt));
} return ;
}

Segment Tree Beats!