Brief
李超树是一种线段树的应用,主要应用场合为:单点集合域,区间等差插入,求单点最值。
For Example
- 动态地插入多条二维线段,询问某个
x
x
x对应的
y
y
y值的最值。
- 修改
[
L
,
R
,
b
,
k
]
[L,R,b,k]
[L,R,b,k],对于第
i
∈
[
L
,
R
]
i\in[L,R]
i∈[L,R]个集合,插入
b
+
(
i
−
L
)
k
b+(i-L)k
b+(i−L)k,询问某个集合的最大值。
Process
- 每个线段树节点记录的是 x = m i d x=mid x=mid时的最值线段。
- 先考虑怎么查询。因为只能记录在 x = m i d x=mid x=mid时的最值线段,所有包含 p o s pos pos的大区间的答案可能不是最优解。所以要递归往下查找,直到 L = R L=R L=R
- 考虑插入一条线段。若区间无线段,则成为最优线段。否则进行比较。
- 设
O
l
d
Old
Old为原线段在
l
l
l上的值,
O
l
d
_
Old\_
Old_为在
r
r
r上的值。
N
e
w
,
N
e
w
_
New,New\_
New,New_同理。
- 简单的情况,
O
l
d
>
N
e
w
,
O
l
d
_
>
N
e
w
_
Old>New,Old\_>New\_
Old>New,Old_>New_或相反时,显然可以直接判断孰优孰劣。
- 考虑存在交点的情况。
- 右图的情况下,交点小于一半,根据两条线的位置关系可以判断,右区间还是原来的线段更优。所以这种情况下,只需要递归的做左边即可。
- 考虑左图的情况,此时当前区间的最值在
n
e
w
new
new上,再结合我们的查询,我们还要记录
o
l
d
old
old(再右半边存在
o
l
d
old
old优于
n
e
w
new
new的情况)。所以将
o
l
d
old
old在右区间往下传递。
- 位置相反的时候也这样考虑一下就行。
Note
- 线段定义域固定时,查询和插入的时间复杂度都是
O
(
l
o
g
n
)
O(logn)
O(logn)。
- 线段定义域不固定时,因为修改区间可能分为
l
o
g
log
log个区间,每个区间可能递归到底,所以插入的时间复杂度为
O
(
l
o
g
2
n
)
O(log^2n)
O(log2n)。查询为
O
(
l
o
g
n
)
O(logn)
O(logn)
- 可以直接使用不固定的代码,时间复杂度该多少就是多少 ,但是它长啊 。
Code(fixed)
problem link - https://www.lydsy.com/JudgeOnline/problem.php?id=1568
题意:
插入 y = k ( x − 1 ) + b y=k(x-1)+b y=k(x−1)+b,求 p o s pos pos上的最大值 m x → m a x ( 0 , m x / 100 ) mx\to max(0,mx/100) mx→max(0,mx/100)
/*
* Author : Jk_Chen
* Date : 2019-09-01-21.19.07
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
#define debug(str) cerr<<#str<<" = "<<str<<'\n';
const LL mod=1e9+7;
const int maxn=5e4+9;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
/*_________________________________________________________head*/
struct line{
bool have;
double k,b;
}tr[maxn<<2];
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
void update(double k,double b,int rt=1,int l=1,int r=5e4){ // insert y=kx+b
if(!tr[rt].have){
tr[rt].k=k,
tr[rt].b=b,
tr[rt].have=1;
return;
}
double Old=tr[rt].k*l+tr[rt].b,Old_=tr[rt].k*r+tr[rt].b;
double New=k*l+b,New_=k*r+b;
if(Old>=New&&Old_>=New_)return;
if(Old<=New&&Old_<=New_){
tr[rt].k=k,
tr[rt].b=b;
return;
}
// k won't equiv tr[rt].k
double pos=-(b-tr[rt].b)/(k-tr[rt].k);
if(Old<=New){
if(pos<=mid){
update(k,b,ls,l,mid);
}
else{
update(tr[rt].k,tr[rt].b,rs,mid+1,r);
tr[rt].k=k,tr[rt].b=b;
}
}
else{
if(pos>=mid){
update(k,b,rs,mid+1,r);
}
else{
update(tr[rt].k,tr[rt].b,ls,l,mid);
tr[rt].k=k,tr[rt].b=b;
}
}
}
double query(int x,int rt=1,int l=1,int r=5e4){ // query most value at x
double ans=-2e18;
if(tr[rt].have)
ans=tr[rt].k*x+tr[rt].b;
if(l==r)return ans;
if(x<=mid)ans=max(ans,query(x,ls,l,mid));
else ans=max(ans,query(x,rs,mid+1,r));
return ans;
}
char str[50];
int main(){
int t=rd();
while(t--){
scanf("%s",str);
if(str[0]=='P'){
double k,b;
scanf("%lf%lf",&b,&k);
update(k,b-k);
}
else{
int x;scanf("%d",&x);
printf("%d\n",max(0,(int)floor(query(x)/100.0)));
}
}
return 0;
}