李超树学习笔记

李超树学习笔记

这东西有点恶心啊,搞了好久才懂一点。
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);
}

但是如果是区间查询则要加上维护区间最小值/最大值的数组:
十分麻烦,是我太蒟蒻了
首先我们要明确区间的最值一般都在两端,
所以我们有些 没有更新下去的要自我用两端的最值更新,

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));
}

由于我们优势线段能不下传就不下传,
所以使某点/某区间最优的线段可能在父区间上,
故要用父区间的和它比较。
单点查询:

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));
}

区间查询:

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;
}
posted @ 2019-10-22 21:28  lsoi_ljk123  阅读(230)  评论(0编辑  收藏  举报