知識點 - 李超樹
解決問題類型:
李超樹是一種線段樹的應用,主要應用場合爲:單點集合域,區間等差插入,求單點最值。
- 動態地插入多條二維線段,詢問某個對應的值的最值。
- 修改,對於第個集合,插入,詢問某個集合的最大值。
實現
-
每個線段樹結點記錄的是 時的最值線段
-
先考慮怎麼查詢。因爲只能記錄 時的最值線段,所有包含pos的大區間的答案可能不是最優解。所以要遞歸的往下查找,直到
-
考慮插入一條線段。若區間無線段,則成爲最優線段。否則進行比較。
-
設爲原線段在上的值,_爲在上的值。 同理。
-
簡單的情況,,或相反時,顯然可以直接判斷孰優孰劣。
-
考慮存在交點的情況。
- 右圖的情況下,交點小於一半,根據兩條線的位置關係可以判斷,右區間還是原來的線段更優。所以這種情況下,只需要遞歸的做左邊即可。
- 考慮左圖的情況,此時當前區間的最值在上,再結合我們的查詢,我們還要記錄(再右半邊存在優於的情況)。所以將在右區間往下傳遞。
- 位置相反的時候也這樣考慮一下就行。
複雜度
- 線段定義域固定時,查詢和插入的時間複雜度都是
- 線段定義域不固定時,因爲修改區間可能分爲個區間,每個區間可能遞歸到底,所以插入的時間複雜度爲查詢複雜度爲
- 查詢爲可以直接使用不固定的代碼,時間複雜度該多少就是多少 ,但是它長啊 。
例題
代碼
#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;
}