李超樹學習筆記

李超樹學習筆記

這東西有點噁心啊,搞了很久才懂一點。
1.有什麼用?
對於一個區間\([l,r]\)每一個點能夠取的權值符合表達式:\(y=kx+b\)的線段
有k條線段覆蓋在全部點上,能夠動態插入線段,求每一個時刻某個點或某個區間的最大/最小值。
它的思想是:儘量不將優點線段下傳,
2.什麼叫優點線段?(假如是使每一個點的值最大)

就是使區間內的取最大值的點最多的線段(固然,咱們每次在實際操做中只是將優點線段與插入線段進行比較,這裏的多條線段只是爲了方便理解,兩條線段的圖以下:)

3.如何實現?
咱們能夠分紅4種狀況討論:(以最大值爲標準)
\(<1>.\)插入線段的斜率大於原有優點線段:
\((1).\)交點在區間中點左邊:

顯然,優點線段改成插入線段,但原優點線段可能在左子區間更優,遞歸。
此時中點處y值插入線段大於原優點線段。
\((2).\)交點在區間中點右邊:

插入線段在此區間沒有原優點線段優,但在右子區間有但願更優,遞歸。
此時中點處y值插入線段小於原優點線段。
\(<2>.\)插入線段的斜率小於原有優點線段:
\((1).\)交點在區間中點左邊:

插入線段在此區間沒有原優點線段優,但在左子區間有但願更優,遞歸。
此時中點處y值插入線段小於原優點線段。
\((2).\)交點在區間中點右邊:

顯然,優點線段改成插入線段,但原優點線段可能在右子區間更優,遞歸。
此時中點處y值插入線段大於原優點線段。
修改大概就這樣,下面是代碼:
單點修改:數組

void update(int l,int r,int id,int x){
    if(l==r){if(f(id,l)>f(tag[x],l)) tag[x]=id; return;}
    int mid=l+r>>1;
    if(line[tag[x]].p>line[id].p){
       if(f(tag[x],mid)<f(id,mid)) update(mid+1,r,tag[x],rc),tag[x]=id;
       else update(l,mid,id,lc);
    }
    else{
       if(f(tag[x],mid)<f(id,mid)) update(l,mid,tag[x],lc),tag[x]=id;
       else update(mid+1,r,id,rc);
    }
}

區間修改:學習

void update(int l,int r,int p,int q,int id,int x){
    int mid=l+r>>1;
    if(p<=l&&r<=q){
       if(l==r){if(f(id,l)>f(tag[x],l)) tag[x]=id; return;}
       if(line[tag[x]].p>line[id].p){
           if(f(tag[x],mid)<f(id,mid)) update(mid+1,r,mid+1,r,tag[x],rc),tag[x]=id;
           else update(l,mid,l,mid,id,lc);
       }
       else{
          if(f(tag[x],mid)<f(id,mid)) update(l,mid,l,mid,tag[x],lc),tag[x]=id;
          else update(mid+1,r,mid+1,r,id,rc);
       }
       return;
    }
    if(p<=mid) update(l,mid,p,q,id,lc);
    if(q>mid) update(mid+1,r,p,q,id,rc);
}

可是若是是區間查詢則要加上維護區間最小值/最大值的數組:
十分麻煩,是我太蒟蒻了
首先咱們要明確區間的最值通常都在兩端,
因此咱們有些 沒有更新下去的要自我用兩端的最值更新,spa

void update(int l,int r,int p,int q,ll k,ll b,int x){
     int mid=l+r>>1;
     if(p<=l&&r<=q){
        if(l==r){if(k*w[l]+b<f(t[x],w[l])) t[x].k=k,t[x].b=b,t[x].minx=f(t[x],w[l]); return;}
        if(k>t[x].k){
           if(k*w[mid]+b<f(t[x],w[mid])) update(mid+1,r,p,q,t[x].k,t[x].b,rc),t[x].k=k,t[x].b=b;
           else update(l,mid,p,q,k,b,lc);
        }
        else{
           if(k*w[mid]+b<f(t[x],w[mid])) update(l,mid,p,q,t[x].k,t[x].b,lc),t[x].k=k,t[x].b=b;
           else update(mid+1,r,p,q,k,b,rc);
        }
        t[x].minx=min(t[x].minx,min(f(t[x],w[l]),f(t[x],w[r]))),t[x].minx=min(t[x].minx,min(t[lc].minx,t[rc].minx));
        return;
     }
     if(p<=mid) update(l,mid,p,q,k,b,lc);
     if(q>mid) update(mid+1,r,p,q,k,b,rc);
     t[x].minx=min(t[x].minx,min(t[lc].minx,t[rc].minx));
}

因爲咱們優點線段能不下傳就不下傳,
因此使某點/某區間最優的線段可能在父區間上,
故要用父區間的和它比較。
單點查詢:3d

double query(int l,int r,int p,int x){
    if(l==r) return f(tag[x],l);
    int mid=l+r>>1; double ans=f(tag[x],p);
    if(p<=mid) return max(ans,query(l,mid,p,lc));
    return max(ans,query(mid+1,r,p,rc));
}

區間查詢:code

ll query(int l,int r,int p,int q,int x){
   if(p<=l&&r<=q) return t[x].minx;
   int mid=l+r>>1; ll ans=inf;
   if(t[x].b!=inf){
      int u=max(l,p),v=min(r,q);
      ans=min(f(t[x],w[u]),f(t[x],w[v]));
   }
   if(p<=mid) ans=min(ans,query(l,mid,p,q,lc));
   if(q>mid) ans=min(ans,query(mid+1,r,p,q,rc));
   return ans;
}
相關文章
相關標籤/搜索