宏定义
- #define pl p<<1:节点 p 的左儿子。
- #define pr p<<1|1:节点 p 的右儿子。
常量与变量
- Tree a[i]:节点 i 的信息。
- int a[i].l:节点 i 维护的区间的左端点。
- int a[i].r:节点 i 维护的区间的右端点。
- long long a[i].k:节点 i 所管理的区间的最优线段的斜率。
- long long a[i].b:节点 i 所管理的区间的最优线段的截距。
函数
- void build(int p,int l,int r):在外调用时,表示以节点 p 为根,建议一颗区间范围为 l∼r 的线段树。
- void change(int p,int l,int r,long long k,long long b):在节点 p 管理的区间中插入一条横坐标区间为 [l,r],斜率为 k,截距为 b 的线段。
- long long ask(int p,int x):求出节点 p 掌管的区间内所有线段的横坐标取 x 时得到的最大的 y 值。
代码
#define pl p<<1
#define pr p<<1|1
struct Segment_Tree{
struct Tree{
int l,r;
long long k,b;
}a[N<<2];
void build(int p,int l,int r){
a[p].l=l;a[p].r=r;
a[p].k=0;a[p].b=0;
if(l==r)
return;
int mid=(l+r)>>1;
build(pl,l,mid);
build(pr,mid+1,r);
}
void change(int p,int l,int r,long long k,long long b){
int mid=(a[p].l+a[p].r)>>1;
if(l<=a[p].l&&a[p].r<=r){
ll x0=a[p].l,x1=a[p].r;
ll py0=a[p].k*x0+a[p].b,py1=a[p].k*x1+a[p].b,py2=a[p].k*mid+a[p].b;
ll ny0=k*x0+b,ny1=k*x1+b,ny2=k*mid+b;
if(ny0>=py0&&ny1>=py1)
a[p].k=k,a[p].b=b;
else if(ny0<=py0&&ny1<=py1)
return;
else{
if(ny0>py0){
if(ny2<py2)
change(pl,l,r,k,b);
else{
change(pr,l,r,a[p].k,a[p].b);
a[p].k=k,a[p].b=b;
}
}
else{
if(ny2>py2){
change(pl,l,r,a[p].k,a[p].b);
a[p].k=k,a[p].b=b;
}
else
change(pr,l,r,k,b);
}
}
return;
}
if(l<=mid)
change(pl,l,r,k,b);
if(r>mid)
change(pr,l,r,k,b);
}
long long ask(int p,int x){
ll ans=x*a[p].k+a[p].b;
if(a[p].l==a[p].r)
return ans;
int mid=(a[p].l+a[p].r)>>1;
if(x<=mid)
ans=max(ans,ask(pl,x));
else
ans=max(ans,ask(pr,x));
return ans;
}
}tree;