题目大意:一条数轴上有n个机器人,对其进行m次操作。操作t_i commond k_i x_i (1≤k_i≤n)
表示ti时刻将第ki个机器人的速度变为正方向上xi格每秒;操作t_i query
则是询问ti时刻离原点最远的机器人到原点的距离(t1≤t2≤t3≤…≤tm,若同一时间发生多次操作,则按读入顺序依次执行)
题目链接:BZOJ3938
题解:以时间为x轴,位置坐标为y轴,commond操作相当于在其中加入一段直线,query操作就是询问某一横坐标对应的y的最大值或最小值的绝对值。离散时间建两棵线段树,分别维护最上方和最下方的线段。超哥线段树简单题。
code(第一棵超哥线段树,代码参考大神咯T^T,加了一点注释,算是我自己对超哥线段树(标记永久化?)的理解)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 600005
using namespace std;
inline int read()
{
char c=getchar(); int num=0,f=1;
while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); }
while (c>='0'&&c<='9') { num=num*10+c-'0'; c=getchar(); }
return num*f;
}
inline long long readl()
{
char c=getchar(); long long num=0,f=1;
while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); }
while (c>='0'&&c<='9') { num=num*10+c-'0'; c=getchar(); }
return num*f;
}
struct opt{
int op,id;
long long k,tm;
}q[N];
long long tagk[N<<2],tagb[N<<2],Tagk[N<<2],Tagb[N<<2];
long long nowk[100005],nowb[100005],b[N],ans1,ans2;
int a[100005],n,m,cnt,num;
bool flag[N<<2],Flag[N<<2];
double cross(long long k1,long long b1,long long k2,long long b2) //求两条直线(斜截式)的交点的横坐标
{
return (b1-b2)/(1.0*(k2-k1));
}
void ins_mx(int now,int l,int r,int L,int R,long long B,long long K) //维护最上方的直线
{
int mid=l+r>>1;
if (L<=l&&r<=R)
{
if (!flag[now]) //是否被直线覆盖过
{
tagk[now]=K,tagb[now]=B,flag[now]=true; return;
}
long long f1=B+K*b[l],f2=tagb[now]+tagk[now]*b[l]; //新插入直线和当前覆盖该区间的直线的左端点的值
long long f3=B+K*b[r],f4=tagb[now]+tagk[now]*b[r]; //新插入直线和当前覆盖该区间的直线的右端点的值
if (f1<=f2&&f3<=f4) return; //新直线完全在当前直线之下,丢弃
if (f1>=f2&&f3>=f4) { tagk[now]=K,tagb[now]=B; return; } //新直线完全在当前直线之上,替换
double xx=cross(K,B,tagk[now],tagb[now]);
if (f1>=f2) //交点左侧新直线更高,右侧当前直线更高
{
if (xx<=b[mid]) ins_mx(now<<1,l,mid,L,R,B,K);
else ins_mx(now<<1|1,mid+1,r,L,R,tagb[now],tagk[now]),tagb[now]=B,tagk[now]=K;
/*在上方时间长的直线保留,短的递归到下一层交点对应的区间*/
}
else /*同理*/
{
if (xx>b[mid]) ins_mx(now<<1|1,mid+1,r,L,R,B,K);
else ins_mx(now<<1,l,mid,L,R,tagb[now],tagk[now]),tagb[now]=B,tagk[now]=K;
}
return;
}
if (L<=mid) ins_mx(now<<1,l,mid,L,R,B,K);
if (R>mid) ins_mx(now<<1|1,mid+1,r,L,R,B,K);
}
void ins_mn(int now,int l,int r,int L,int R,long long B,long long K)
{
int mid=l+r>>1;
if (L<=l&&r<=R)
{
if (!Flag[now])
{
Tagk[now]=K,Tagb[now]=B,Flag[now]=true; return;
}
long long f1=B+K*b[l],f2=Tagb[now]+Tagk[now]*b[l];
long long f3=B+K*b[r],f4=Tagb[now]+Tagk[now]*b[r];
if (f1>=f2&&f3>=f4) return;
if (f1<=f2&&f3<=f4) { Tagk[now]=K,Tagb[now]=B; return; }
double xx=cross(K,B,Tagk[now],Tagb[now]);
if (f1<=f2)
{
if (xx<=b[mid]) ins_mn(now<<1,l,mid,L,R,B,K);
else ins_mn(now<<1|1,mid+1,r,L,R,Tagb[now],Tagk[now]),Tagb[now]=B,Tagk[now]=K;
}
else
{
if (xx>b[mid]) ins_mn(now<<1|1,mid+1,r,L,R,B,K);
else ins_mn(now<<1,l,mid,L,R,Tagb[now],Tagk[now]),Tagb[now]=B,Tagk[now]=K;
}
return;
}
if (L<=mid) ins_mn(now<<1,l,mid,L,R,B,K);
if (R>mid) ins_mn(now<<1|1,mid+1,r,L,R,B,K);
}
void query_mx(int now,int l,int r,int pos) //查询最大值
{
if (flag[now]) ans1=max(ans1,tagb[now]+tagk[now]*b[pos]);
/*线段树中每个区间都对应着一条不同的线段(或者未被完全覆盖),对覆盖pos的log n条线段在pos处的取值取max,即是答案*/
if (l==r) return;
int mid=l+r>>1;
if (pos<=mid) query_mx(now<<1,l,mid,pos);
else query_mx(now<<1|1,mid+1,r,pos);
}
void query_mn(int now,int l,int r,int pos)
{
if (Flag[now]) ans2=min(ans2,Tagb[now]+Tagk[now]*b[pos]);
if (l==r) return;
int mid=l+r>>1;
if (pos<=mid) query_mn(now<<1,l,mid,pos);
else query_mn(now<<1|1,mid+1,r,pos);
}
int main()
{
n=read(); m=read();
for (int i=1;i<=n;i++) nowb[i]=readl(),nowk[i]=0ll,a[i]=0;
for (int i=1;i<=m;i++)
{
b[i]=q[i].tm=readl();
char s[10]; scanf("%s",s);
if (s[0]=='c') q[i].id=read(),q[i].k=readl(),q[i].op=1;
else q[i].op=0;
}
num=m; b[++num]=0; sort(b+1,b+num+1); cnt=unique(b+1,b+num+1)-b-1;
for (int i=1;i<=m;i++)
if (q[i].op==1)
{
int x=q[i].id,lst=lower_bound(b+1,b+cnt+1,a[x])-b;
int now=lower_bound(b+1,b+cnt+1,q[i].tm)-b;
ins_mx(1,1,cnt,lst,now,nowb[x],nowk[x]);
ins_mn(1,1,cnt,lst,now,nowb[x],nowk[x]);
nowb[x]=nowb[x]+q[i].tm*(nowk[x]-q[i].k);
nowk[x]=q[i].k; a[x]=q[i].tm;
}
for (int i=1;i<=n;i++)
{
int lst=lower_bound(b+1,b+cnt+1,a[i])-b;
ins_mx(1,1,cnt,lst,cnt,nowb[i],nowk[i]);
ins_mn(1,1,cnt,lst,cnt,nowb[i],nowk[i]);
}
for (int i=1;i<=m;i++)
if (q[i].op==0)
{
ans1=ans2=0;
int now=lower_bound(b+1,b+cnt+1,q[i].tm)-b;
query_mx(1,1,cnt,now);
query_mn(1,1,cnt,now);
printf("%lld\n",max(ans1,-ans2));
}
return 0;
}