bzoj3938 Robot
3938: Robot
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 336 Solved: 112
[Submit][Status][Discuss]
Description
小q有n只机器人,一开始他把机器人放在了一条数轴上,第i只机器人在ai的位置上静止,而自己站在原点。在这
之后小q会执行一些操作,他想要命令一个机器人向左或者向右移动x格。但是机器人似乎听不清小q的命令,事实
上它们会以每秒x格的速度匀速移动。看着自己的机器人越走越远,小q很着急,他想知道当前离他(原点)最远的
机器人有多远。具体的操作以及询问见输入格式。注意,不同的机器人之间互不影响,即不用考虑两个机器人撞在
了一起的情况。
Input
共有m个事件,输入将会按事件的时间顺序给出。第一行两个正整数n,m。接下来一行n个整数,第i个数是ai,表示
第i个机器人初始的位置(初始移动速度为0)。接下来m行,每行行首是一个非负整数ti,表示该事件点发生的时
刻(以秒为单位)。第二个是一个字符串S,代表操作的种类。数字与字符串之间用一个空格隔开。接下来的输入
按S的种类分类。若S是“command”(不带引号),则接下来两个整数ki,xi,表示小q对第ki个机器人执行了操作
,该机器人的速度将会被重置,变为向数轴正方向每秒移动xi格(若xi为负数就相当于向数轴负方向每秒移动∣xi
∣格)。保证1≤ki≤n。若S是“query”(不带引号),则你需要输出当前离原点最远的机器人有多远。保证t1≤
t2≤t2≤...≤tm。(注:若同一时间发生多次操作,则按读入顺序依次执行)
Output
对于每个query询问,输出一行,包含一个整数表示正确的答案。C/C++输入输出longlong时请用%lld。由于本题数
据量较大,建议不要使用cin/cout进行输入输出。
Sample Input
4 5
-20 0 20 100
10 command 1 10
20 command 3 -10
30 query
40 command 1 -30
50 query
-20 0 20 100
10 command 1 10
20 command 3 -10
30 query
40 command 1 -30
50 query
Sample Output
180
280
280
HINT
第一个命令执行时,各个机器人的位置为:−20,0,20,100。
第二个命令执行时,各个机器人的位置为:80,0,20,100。
第一个询问时,各个机器人的位置为:180,0,−80,100。
第三个命令执行时,各个机器人的位置为:280,0,−180,100。
第二个询问时,各个机器人的位置为:−20,0,−280,100。
限制与约定
设 command 的个数为 C,query 的个数为 Q。(所以 C+Q=m)
对于所有的事件满足 0≤ti≤10^9,对于所有的 command 满足 ∣xi∣≤10^4。
对于所有的机器人满足 ∣ai∣≤10^9。
N,C<=10^5
Q<=5*10^5
Source
分析:这道题和bzoj1568差不多,将t看做横坐标,相对于原点的距离看做纵坐标,最后求最大值和最小值,取各自绝对值的最大值,无非就是把直线改成了一条条的折线段.折线段的处理比较麻烦,比较考验细节处理能力.转化完后做法就基本上是一样的了.
一些细节地方在代码中有注释
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const ll maxn = 600010; ll n,m; ll Tim[maxn],v[maxn],d[maxn],cnt,Time[maxn],ans1,ans2; bool vis1[maxn << 2],vis2[maxn << 2]; struct node { ll Time,V; ll opt,pos; } a[maxn]; struct node2 { ll k,b; ll id; } e1[maxn << 2],e2[maxn << 2]; double jiao(node2 a,node2 b) { return (double)(a.b - b.b) / (b.k - a.k); } bool cmp(node2 a,node2 b,ll pos) { return a.k * pos + a.b < b.k * pos + b.b; } void update1(int o,int l,int r,int x,int y,node2 a) { int mid = (l + r) >> 1; if (x <= l && r <= y) { if (!vis1[o]) { vis1[o] = 1; e1[o] = a; } else { ll l1 = a.b + a.k * Tim[l],l2 = a.b + a.k * Tim[r]; ll r1 = e1[o].b + e1[o].k * Tim[l],r2 = e1[o].b + e1[o].k * Tim[r]; if (l1 <= r1 && l2 <= r2) return; if (l1 >= r1 && l2 >= r2) e1[o] = a; else { double X = jiao(a,e1[o]); if (l1 >= r1) { if (X <= Tim[mid]) update1(o * 2,l,mid,x,y,a); else update1(o * 2 + 1,mid + 1,r,x,y,e1[o]),e1[o] = a; } else { if (X > Tim[mid]) update1(o * 2 + 1,mid + 1,r,x,y,a); else update1(o * 2,l,mid,x,y,e1[o]),e1[o] = a; } } } return; } if (x <= mid) update1(o * 2,l,mid,x,y,a); if (y > mid) update1(o * 2 + 1,mid + 1,r,x,y,a); } void update2(int o,int l,int r,int x,int y,node2 a) { int mid = (l + r) >> 1; if (x <= l && r <= y) { if (!vis2[o]) { vis2[o] = 1; e2[o] = a; } else { ll l1 = a.b + a.k * Tim[l],l2 = a.b + a.k * Tim[r]; ll r1 = e2[o].b + e2[o].k * Tim[l],r2 = e2[o].b + e2[o].k * Tim[r]; if (l1 >= r1 && l2 >= r2) return; if (l1 <= r1 && l2 <= r2) e2[o] = a; else { double X = jiao(a,e2[o]); if (l1 <= r1) { if (X <= Tim[mid]) update2(o * 2,l,mid,x,y,a); else update2(o * 2 + 1,mid + 1,r,x,y,e2[o]),e2[o] = a; } else { if (X > Tim[mid]) update2(o * 2 + 1,mid + 1,r,x,y,a); else update2(o * 2,l,mid,x,y,e2[o]),e2[o] = a; } } } return; } if (x <= mid) update2(o * 2,l,mid,x,y,a); if (y > mid) update2(o * 2 + 1,mid + 1,r,x,y,a); } node2 query1(ll o,ll l,ll r,ll pos) { if (l == r) return e1[o]; ll mid = (l + r) >> 1; node2 temp; if (pos <= mid) temp = query1(o * 2,l,mid,pos); else temp = query1(o * 2 + 1,mid + 1,r,pos); if (cmp(temp,e1[o],Tim[pos])) return e1[o]; else return temp; } node2 query2(ll o,ll l,ll r,ll pos) { if (l == r) return e2[o]; ll mid = (l + r) >> 1; node2 temp; if (pos <= mid) temp = query2(o * 2,l,mid,pos); else temp = query2(o * 2 + 1,mid + 1,r,pos); if (cmp(temp,e2[o],Tim[pos])) return temp; else return e2[o]; } int main() { scanf("%lld%lld",&n,&m); for (ll i = 1; i <= n; i++) scanf("%lld",&d[i]); for (ll i = 1; i <= m; i++) { scanf("%lld",&Tim[i]); a[i].Time = Tim[i]; char ch[10]; scanf("%s",ch); if (ch[0] == 'c') { a[i].opt = 1; scanf("%lld%lld",&a[i].pos,&a[i].V); } else a[i].opt = 0; } cnt = m + 1; Tim[cnt] = 0; //为了插入初始线段,加一个Tim = 0 sort(Tim + 1,Tim + 1 + cnt); cnt = unique(Tim + 1,Tim + 1 + cnt) - Tim - 1; //去重离散化 for (ll i = 1; i <= m; i++) if (a[i].opt == 1) { ll pos = a[i].pos; ll l = lower_bound(Tim + 1,Tim + 1 + cnt,Time[pos]) - Tim; ll r = lower_bound(Tim + 1,Tim + 1 + cnt,a[i].Time) - Tim; node2 temp; temp.k = v[pos]; //线段的斜率和截距 temp.b = d[pos]; update1(1,1,cnt,l,r,temp); update2(1,1,cnt,l,r,temp); d[pos] += a[i].Time * (v[pos] - a[i].V); //新线段的截距.至于怎么求的,利用两条直线的交点列方程.a[i].Time就是交点横坐标 v[pos] = a[i].V; //v是记录上一次的斜率 Time[pos] = a[i].Time; //记录上一次这个机器人更改的时间 } for (ll i = 1; i <= n; i++) { ll l = lower_bound(Tim + 1,Tim + 1 + cnt,Time[i]) - Tim; node2 temp; temp.k = v[i]; temp.b = d[i]; update1(1,1,cnt,l,cnt,temp); //最后一条线段变成一条射线,延伸到右端点 update2(1,1,cnt,l,cnt,temp); } for (ll i = 1; i <= m; i++) if (a[i].opt == 0) { ll l = lower_bound(Tim + 1,Tim + 1 + cnt,a[i].Time) - Tim; node2 temp1 = query1(1,1,cnt,l); node2 temp2 = query2(1,1,cnt,l); ll ans1 = temp1.k * Tim[l] + temp1.b; ll ans2 = temp2.k * Tim[l] + temp2.b; printf("%lld\n",max(ans1,-ans2)); } return 0; }