线段树区间(min space & & space max) 总结
有一种题目,让我们求区间取 (min) 和取 (max)
然后又求和或者其它的操作
笔者没有见过区间取 (min) 和取 (max) 和其它复杂操作的混合题
例题:(BZOJ4636) 蒟蒻的数列
区间取(max+)求和(默认离散化不是一个复杂知识点)
维护 (3) 个新的 (tag)
1.区间最小(或者大)值
2.区间次小(或者大)值
3.区间最值的个数
这三个 (tag) 的合并方式不是很复杂,直接上代码理解一下:
inline void push_up(int p)
{
sum(p)=sum(p<<1)+sum(p<<1|1);
num(p)=0; maxx(p)=max(maxx(p<<1|1),maxx(p<<1));
se(p)=max(se(p<<1),se(p<<1|1));
if(maxx(p<<1)!=maxx(p<<1|1)) se(p)=max(se(p),min(maxx(p),maxx(p<<1|1)));
if(maxx(p)==maxx(p<<1)) num(p)+=num(p<<1);
if(maxx(p)==maxx(p<<1|1)) num(p)+=num(p<<1|1);
return ;
}
然后我们这种题目在修改的时候分几种情况讨论:
1.修改的新 (val) 比最值还最值(省略大小)
修改并没用,直接返回
2.比次最值最值,没有最值最值
(意会吧)
我们更新一下节点的 (sum),(sum)的更新方式也不难理解,毕竟我们维护了 (num)
inline void clear(int p,int val)
{
if(maxx(p)<=val) return ;
sum(p)+=1ll*(val-maxx(p))*num(p);
maxx(p)=val;
}
(push\_down) 的时候就两个子树和父节点的最值 (clear) 就 (OK) 了
然后就是基础操作了(什么?不会? 转去 (Luogu) 模板区吧)
直接放代码,真的真的好简单,看一遍就能背过(其实就是理解一下,根本不用背)
(Code:)
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=1e5+10;
struct node{
int l,r,sum,minn,se,num;
#define l(p) t[p].l
#define r(p) t[p].r
#define sum(p) t[p].sum
#define minn(p) t[p].minn
#define se(p) t[p].se
#define num(p) t[p].num
}t[N<<2];
inline void push_up(int p)
{
sum(p)=sum(p<<1)+sum(p<<1|1);
minn(p)=min(minn(p<<1),minn(p<<1|1));
se(p)=min(se(p<<1|1),se(p<<1)); num(p)=0;
if(minn(p<<1)!=minn(p<<1|1)) se(p)=min(se(p),max(minn(p<<1),minn(p<<1|1)));
if(minn(p)==minn(p<<1|1)) num(p)+=num(p<<1|1);
if(minn(p)==minn(p<<1)) num(p)+=num(p<<1);
return ;
}
inline void build(int p,int l,int r)
{
l(p)=l; r(p)=r;
if(l==r) return num(p)=1,minn(p)=0,sum(p)=0,se(p)=1e15+10,void();
int mid=(l+r)>>1;
build(p<<1,l,mid); build(p<<1|1,mid+1,r);
return push_up(p);
}
inline void clear(int p,int val)
{
if(val<=minn(p)) return ;
sum(p)+=(val-minn(p))*num(p);
minn(p)=val;
return ;
}
inline void spread(int p)
{
clear(p<<1,minn(p)); clear(p<<1|1,minn(p));
return ;
}
inline void change(int p,int l,int r,int d)
{
if(l<=l(p)&&r(p)<=r&&d<se(p)) return clear(p,d);
spread(p); int mid=(l(p)+r(p))>>1;
if(l<=mid) change(p<<1,l,r,d);
if(r>mid) change(p<<1|1,l,r,d);
return push_up(p);
}
inline int ask(int p,int x,int d)
{
if(l(p)==x&&r(p)==x) return sum(p);
spread(p);
int mid=(l(p)+r(p))>>1;
if(x<=mid) return ask(p<<1,x,d);
else return ask(p<<1|1,x,d);
}
int pos[N],m,l[N],r[N],d[N];
signed main()
{
int n=read();
for(int i=1;i<=n;++i)
{
l[i]=read(); r[i]=read(); d[i]=read();
pos[++m]=l[i]; pos[++m]=r[i];
}
sort(pos+1,pos+m+1); m=unique(pos+1,pos+m+1)-pos-1;
for(int i=1;i<=n;++i)
{
l[i]=lower_bound(pos+1,pos+m+1,l[i])-pos;
r[i]=lower_bound(pos+1,pos+m+1,r[i])-pos;
}build(1,1,m);
for(int i=1;i<=n;++i){
change(1,l[i],r[i]-1,d[i]);
}
int ans=0;
for(int i=1;i<=m;++i)
{
int res=ask(1,i,i);
ans+=res*(pos[i+1]-pos[i]);
} printf("%lld
",ans);
return 0;
}
}
signed main(){return yspm::main();}