bzoj3938 Robot

3938: Robot

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 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

Sample Output

180
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;
}

 

posted @ 2018-02-09 11:26  zbtrs  阅读(253)  评论(0编辑  收藏  举报