知識點 - 李超樹

原文鏈接:https://blog.csdn.net/jk_chen_acmer/article/details/100364193

知識點 - 李超樹

解決問題類型:

李超樹是一種線段樹的應用,主要應用場合爲:單點集合域,區間等差插入,求單點最值。

  • 動態地插入多條二維線段,詢問某個xx對應的yy值的最值。
  • 修改[L,R,b,k][L,R,b,k],對於第i[L,R]i∈[L,R]個集合,插入b+(iL)kb+(i−L)k,詢問某個集合的最大值。

實現

  1. 每個線段樹結點記錄的是 x=midx = mid 時的最值線段

  2. 先考慮怎麼查詢。因爲只能記錄 x=midx = mid 時的最值線段,所有包含pos的大區間的答案可能不是最優解。所以要遞歸的往下查找,直到L=RL=R

  3. 考慮插入一條線段。若區間無線段,則成爲最優線段。否則進行比較。

  4. OldOld爲原線段在ll上的值,OldOld_爲在rr上的值。NewNew 同理。

  5. 簡單的情況,Old>NewOld >New,Old_>New_Old\_ > New\_或相反時,顯然可以直接判斷孰優孰劣。

  6. 考慮存在交點的情況。

在这里插å¥å›¾ç‰‡æè¿°

  • 右圖的情況下,交點小於一半,根據兩條線的位置關係可以判斷,右區間還是原來的線段更優。所以這種情況下,只需要遞歸的做左邊即可。
  • 考慮左圖的情況,此時當前區間的最值在newnew上,再結合我們的查詢,我們還要記錄oldold(再右半邊存在oldold優於newnew的情況)。所以將oldold在右區間往下傳遞。
  • 位置相反的時候也這樣考慮一下就行。

複雜度

  • 線段定義域固定時,查詢和插入的時間複雜度都是O(logn)O(logn)
  • 線段定義域不固定時,因爲修改區間可能分爲loglog個區間,每個區間可能遞歸到底,所以插入的時間複雜度爲O(log2n)O(log^2n)查詢複雜度爲O(logn)O(logn)
  • 查詢爲O(logn)O(logn)可以直接使用不固定的代碼,時間複雜度該多少就是多少 ,但是它長啊 。

例題

BZOJ 1568

代碼

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章