bzoj3938 Robot(李超线段树+离散化)

水题写一年系列。
每个机器人的位置随时间的函数应该是个分段函数,每一段都是一次函数。
我们可以离线,把时间离散化掉,就是维护若干线段的最值。
可以先都插进去,然后最后处理询问。
可以用李超线段树来解决。分别维护最大最小值。
复杂度 O(nlog2n)

#include 
#include 
#include 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int nn,n,lst[N],Q[N*5],aa[N*6],m,n1,n2,now[N];
char s[N];
struct Line{
    ll k,b;
    ll f(ll x){return k*x+b;}
}a[N*3];
struct oper{
    int tim,x,k;
}O[N];
struct node{
    int x,y;
}tr[N*6*4];
inline void ins(int p,int l,int r,int x,int y,int id){//最大值
    if(x<=l&&r<=y){
        if(!tr[p].x){tr[p].x=id;return;}
        ll fl=a[tr[p].x].f(aa[l])-a[id].f(aa[l]),fr=a[tr[p].x].f(aa[r])-a[id].f(aa[r]);
        if(fl>=0&&fr>=0) return;
        if(fl<0&&fr<0){tr[p].x=id;return;}int mid=l+r>>1;
        if(fl>0){
            if(a[tr[p].x].f(aa[mid])>a[id].f(aa[mid])) ins(p<<1|1,mid+1,r,x,y,id);
            else ins(p<<1,l,mid,x,y,tr[p].x),tr[p].x=id;
        }else{
            if(a[tr[p].x].f(aa[mid])>a[id].f(aa[mid])) ins(p<<1,l,mid,x,y,id);
            else ins(p<<1|1,mid+1,r,x,y,tr[p].x),tr[p].x=id;
        }return;
    }int mid=l+r>>1;
    if(x<=mid) ins(p<<1,l,mid,x,y,id);
    if(y>mid) ins(p<<1|1,mid+1,r,x,y,id);
}
inline void ins1(int p,int l,int r,int x,int y,int id){//最小值
    if(x<=l&&r<=y){
        if(!tr[p].y){tr[p].y=id;return;}
        ll fl=a[tr[p].y].f(aa[l])-a[id].f(aa[l]),fr=a[tr[p].y].f(aa[r])-a[id].f(aa[r]);
        if(fl<=0&&fr<=0) return;
        if(fl>0&&fr>0){tr[p].y=id;return;}int mid=l+r>>1;
        if(fl>0){
            if(a[tr[p].y].f(aa[mid])1,l,mid,x,y,id);
            else ins1(p<<1|1,mid+1,r,x,y,tr[p].y),tr[p].y=id;
        }else{
            if(a[tr[p].y].f(aa[mid])1|1,mid+1,r,x,y,id);
            else ins1(p<<1,l,mid,x,y,tr[p].y),tr[p].y=id;
        }return;
    }int mid=l+r>>1;
    if(x<=mid) ins1(p<<1,l,mid,x,y,id);
    if(y>mid) ins1(p<<1|1,mid+1,r,x,y,id);
}
inline ll askmn(int p,int l,int r,int x){
    if(l==r) return a[tr[p].y].f(aa[x]);
    int mid=l+r>>1;
    if(x<=mid) return min(askmn(p<<1,l,mid,x),a[tr[p].y].f(aa[x]));
    return min(askmn(p<<1|1,mid+1,r,x),a[tr[p].y].f(aa[x]));
}
inline ll askmx(int p,int l,int r,int x){
    if(l==r) return a[tr[p].x].f(aa[x]);
    int mid=l+r>>1;
    if(x<=mid) return max(askmx(p<<1,l,mid,x),a[tr[p].x].f(aa[x]));
    return max(askmx(p<<1|1,mid+1,r,x),a[tr[p].x].f(aa[x]));
}
int main(){
//  freopen("a.in","r",stdin);
    nn=read();m=read();
    for(int i=1;i<=nn;++i) a[i].b=read(),now[i]=i;
    for(int i=1;i<=m;++i){
        aa[i]=read();scanf("%s",s+1);
        if(s[1]=='c') O[++n1].tim=aa[i],O[n1].x=read(),O[n1].k=read();
        else Q[++n2]=aa[i];
    }aa[++m]=0;sort(aa+1,aa+m+1);n=unique(aa+1,aa+m+1)-aa-1;m=nn;
    for(int i=1;i<=n1;++i){
        int x=O[i].x,l=lower_bound(aa+1,aa+n+1,lst[x])-aa,r=lower_bound(aa+1,aa+n+1,O[i].tim)-aa;
        ins(1,1,n,l,r,now[x]);ins1(1,1,n,l,r,now[x]);
        a[++m].k=O[i].k;a[m].b=a[now[x]].b+O[i].tim*(a[now[x]].k-a[m].k);
        now[x]=m;lst[x]=O[i].tim;
    }for(int i=1;i<=nn;++i){
        int l=lower_bound(aa+1,aa+n+1,lst[i])-aa;
        ins(1,1,n,l,n,now[i]);ins1(1,1,n,l,n,now[i]);
    }for(int i=1;i<=n2;++i){
        int x=lower_bound(aa+1,aa+n+1,Q[i])-aa;
        ll ans=max(-askmn(1,1,n,x),askmx(1,1,n,x));
        printf("%lld\n",ans);
    }return 0;
}

你可能感兴趣的:(bzoj,线段树)