BZOJ1568:[JSOI2008]Blue Mary开公司

浅谈标记永久化:https://www.cnblogs.com/AKMer/p/10137227.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1568

什么是李超线段树?李超线段树就是用标记永久化维护平面内线段覆盖的线段树。

对于这个题,对于每个区间,我们可以存下来在这个区间的中点\(y\)值最大的直线。

对于添加一条线段,我们在线段树上对其进行递归替换原有标记:

如果当前线段的斜率大于当前区间标记线段的斜率:

如果在中点当前线段更大,由于斜率更大,说明在中点及中点以后的部分中,当前线段会比标记线段更优,我们先用标记线段去替换更新中点以前的部分,再把当前线段变成当前区间的标记线段。

否则,递归用当前线段去替换更新中点以后的区间。

如果当前线段的斜率小于当前区间标记线段的斜率:

如果在中点当前线段更大,由于斜率更小,说明在中点及中点以前的部分中,当前线段会比标记线段更优,我们先用标记线段去替换更新中点以后的部分,再把当前线段变成当前区间的标记线段。
否则,递归用当前线段去替换更新中点以前的区间。

对于询问,就拿一个一个区间标记的直线算算取最大值就行了。

时间复杂度:\(O(NlogT)\)

空间复杂度:\(O(T)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
 
const int maxn=5e4+5;
 
int n,tot;
char s[10];
double b[maxn<<1],k[maxn<<1];
 
int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}
 
inline double calc(int id,int x) {
    return b[id]+k[id]*(x-1);
}
 
struct segment_tree {
    int tag[maxn<<2];
 
    void change(int p,int l,int r,int id) {
        if(l==r) {
            if(calc(id,l)>calc(tag[p],l))tag[p]=id;
            return;
        }
        int mid=(l+r)>>1;
        if(k[id]>k[tag[p]]) {
            if(calc(id,mid)>calc(tag[p],mid))change(p<<1,l,mid,tag[p]),tag[p]=id;
            else change(p<<1|1,mid+1,r,id);
        }
        else {
            if(calc(id,mid)>calc(tag[p],mid))change(p<<1|1,mid+1,r,tag[p]),tag[p]=id;
            else change(p<<1,l,mid,id);
        }
    }
 
    double query(int p,int l,int r,int pos) {
        if(l==r)return calc(tag[p],l);
        int mid=(l+r)>>1;double ans=calc(tag[p],pos);
        if(pos<=mid)ans=max(ans,query(p<<1,l,mid,pos));
        else ans=max(ans,query(p<<1|1,mid+1,r,pos));
        return ans;
    }
}T;
 
int main() {
    n=read();
    for(int i=1;i<=n;i++) {
        scanf("%s",s+1);
        if(s[1]=='Q') {
            int pos=read();
            double ans=T.query(1,1,5e4,pos);
            printf("%d\n",(int)(ans/100));
        }
        else {
            tot++;
            scanf("%lf%lf",b+tot,k+tot);
            T.change(1,1,5e4,tot);
        }
    }
    return 0;
}
posted @ 2018-12-18 16:51  AKMer  阅读(275)  评论(0编辑  收藏  举报