P11728 [集训队互测 2015] Robot
先看测试点 command 操作,此时若以时间
但当 command 操作时,该轨迹又会变成一条折线,极为不美观,此时若把折线分成若干线段,则每条线段仍满足上面的性质,但有定义域的限制。
因此考虑离线,将每个机器人的轨迹分为若干线段存储,线段总数为
现在题目转化为:
现有
n+C 条形如x=kt+b,t \in[l,r] 的线段,Q 次询问,每次给定一个数t_i ,求与直线t=t_i 相交的线段中,交点纵坐标最大为多少。
显然是李超线段树,但交点坐标均为整数,比模版P4097 【模板】李超线段树还是好写点的。
注意:
附代码:
#include<bits/stdc++.h>
using namespace std;
#define ls tr[p].l
#define rs tr[p].r
typedef long long ll;
typedef long double ld;
const int N=1e5+10;
struct line{
int k;ll b;
}p[N<<2];
int cnt=0;
ll f(int id,int x){
return labs(1ll*p[id].k*x+p[id].b);
}
struct tree{
int l,r,id;
}tr[N<<5];
int tot=0,rt=0;
void pushnow(int &p,int l,int r,int now){
if(!p) p=++tot;
int &lst=tr[p].id,mid=(l+r)>>1;
if(f(now,mid)>f(lst,mid)) swap(now,lst);
if(f(now,l)>f(lst,l)) pushnow(ls,l,mid,now);
if(f(now,r)>f(lst,r)) pushnow(rs,mid+1,r,now);
}
void update(int &p,int l,int r,int ql,int qr,int now){
if(!p) p=++tot;
if(ql<=l&&r<=qr) return pushnow(p,l,r,now),void();
int mid=(l+r)>>1;
if(ql<=mid) update(ls,l,mid,ql,qr,now);
if(qr>mid) update(rs,mid+1,r,ql,qr,now);
}
ll query(int p,int l,int r,int pl){
if(!p) return 0;
ll res=f(tr[p].id,pl);
int mid=(l+r)>>1;
if(pl<=mid) return max(res,query(ls,l,mid,pl));
else return max(res,query(rs,mid+1,r,pl));
}
int n,m,mxt=0,a[N];
vector<pair<int,int> > ch[N];
vector<int> q;
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
ch[i].push_back({0,0});
}
int t,k,x; string s;
for(int i=1;i<=m;i++){
cin>>t>>s;
mxt=max(mxt,t);
if(s[0]=='c'){
cin>>k>>x;
if((*ch[k].rbegin()).first==t) ch[k].pop_back();
ch[k].push_back({t,x});
}
else q.push_back(t);
}
for(int i=1;i<=n;i++){
if((*ch[i].rbegin()).first!=mxt) ch[i].push_back({mxt,0});
ll y=a[i];
for(int j=1;j<(int)ch[i].size();j++){
int l=ch[i][j-1].first,r=ch[i][j].first,k=ch[i][j-1].second;
p[++cnt]={k,y-1ll*k*l};
y+=1ll*(r-l)*k;
update(rt,0,mxt,l,r,cnt);
}
}
for(auto i:q)
cout<<query(1,0,mxt,i)<<'\n';
return 0;
}