BZOJ3938:Robot

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

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

首先,操作的个数小于等于\(6*10^5\),因为这个我对着我的程序干瞪眼白白浪费了半个晚上和半个早上。

另外,由于是求离原点距离最远的,所以应该把所有的线段都移到\(y\)的正半轴上来。

转化题意:对于\(i\)号机器人从第\(x\)秒到第\(y\)秒都按照\(k\)的速度移动,第\(x\)秒在\(st\),第\(y\)秒在\(ed\),我们可以算出一次函数的\(b\),然后在一次函数\(y=kx+b\)上面截取\(x\)\(y\)丢到李超线段树里去维护。

最后,这题跟BZOJ3165:[HEOI2013]Segment基本一样。

时间复杂度:\(O(nlog^2n)\)

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

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
 
const int maxn=6e5+5;
 
int n,m,cnt,tot;
int pos[maxn],nxt[maxn],tim[maxn*4];
int a[maxn],t[maxn],opt[maxn],id[maxn],x[maxn];
 
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;
}
 
struct Line {
    ll b;
    int st,ed,k;
 
    Line() {}
 
    Line(int _st,int _ed,ll _b,int _k) {
        st=_st,ed=_ed,b=_b,k=_k;
    }
}line[maxn*4];
 
struct segment_tree {
    int tag[maxn<<3];
 
    ll calc(int id,int x) {
        return line[id].b+1ll*x*line[id].k;
    }
 
    bool check(int id1,int id2,int x) {
        return calc(id1,x)<calc(id2,x);
    }
 
    ll query(int p,int l,int r,int pos) {
        if(l==r)return calc(tag[p],tim[l]);
        int mid=(l+r)>>1;ll ans=calc(tag[p],tim[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;
    }
 
    void change(int p,int l,int r,int id) {
        if(l==r) {
            if(check(tag[p],id,tim[l]))tag[p]=id;
            return;
        }
        int mid=(l+r)>>1;
        if(line[id].k>line[tag[p]].k) {
            if(check(tag[p],id,tim[mid]))change(p<<1,l,mid,tag[p]),tag[p]=id;
            else change(p<<1|1,mid+1,r,id);
        }
        else if(line[id].k==line[tag[p]].k) {
            if(check(tag[p],id,tim[mid]))tag[p]=id;
        }
        else {
            if(check(tag[p],id,tim[mid]))change(p<<1|1,mid+1,r,tag[p]),tag[p]=id;
            else change(p<<1,l,mid,id);
        }
    }
 
    void ins(int p,int l,int r,int L,int R,int id) {
        if(L<=l&&r<=R) {change(p,l,r,id);return;}
        int mid=(l+r)>>1;
        if(L<=mid)ins(p<<1,l,mid,L,R,id);
        if(R>mid)ins(p<<1|1,mid+1,r,L,R,id);
    }
    }T;
 
void make_line(int l,int r,ll B,int K) {
    l=t[l],r=t[r];
    ll st=B,ed=B+1ll*K*(r-l);B=ed-1ll*r*K;
    if(st<=0&&ed<=0)line[++cnt]=Line(l,r,-B,-K);
    else if(st>=0&&ed>=0)line[++cnt]=Line(l,r,B,K);
    else {
        int T=(-B)/K;tim[++tot]=T;
        if(st>=0)line[++cnt]=Line(l,T,B,K),line[++cnt]=Line(T+1,r,-B,-K);
        else line[++cnt]=Line(l,T,-B,-K),line[++cnt]=Line(T+1,r,B,K);
    }
}
 
void solve_lines() {
    for(int i=1;i<=n;i++) {
        make_line(1,pos[i],a[i],0);
        int now=pos[i];ll B=a[i];
        while(now<m) {
            make_line(now,nxt[now],B,x[now]);
            B=B+1ll*x[now]*(t[nxt[now]]-t[now]);
            now=nxt[now];
        }
    }
}
 
int main() {
    n=read(),tot=m=read();
    for(int i=1;i<=n;i++)
        a[i]=read(),pos[i]=m;
    for(int i=1;i<=m;i++) {
        tim[i]=t[i]=read();
        char s[20];scanf("%s",s+1);
        if(s[1]=='q')opt[i]=1;
        else opt[i]=2;
        if(opt[i]==2)id[i]=read(),x[i]=read();
    }
    for(int i=m;i;i--)
        if(opt[i]==2)nxt[i]=pos[id[i]],pos[id[i]]=i;
    solve_lines();sort(tim+1,tim+tot+1);
    int num=unique(tim+1,tim+tot+1)-tim-1;
    tot=num;
    for(int i=1;i<=cnt;i++) {
        int l=lower_bound(tim+1,tim+tot+1,line[i].st)-tim;
        int r=lower_bound(tim+1,tim+tot+1,line[i].ed)-tim;
        T.ins(1,1,tot,l,r,i);
    }
    for(int i=1;i<=m;i++)
        if(opt[i]==1) {
            int q=lower_bound(tim+1,tim+tot+1,t[i])-tim;
            printf("%lld\n",T.query(1,1,tot,q));
        }
    return 0;
}

转载于:https://www.cnblogs.com/AKMer/p/10166817.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值