UOJ 88 [集训队互测2015]Robot

线段树分治套凸包

每个机器人在多次修改之间的贡献是不同的,因为这个一次函数被修改。显然要线段树分治。

我们需要在线段树上维护凸壳,刚开始我以为要用动态凸包的那套理论。后来才知道直接在外面给所有一次函数排序,做凸壳就能是线性的了。。。我真智障

这个代码常数太大,在UOJ上排倒二,你们还是别(另)看(请)了(高)吧(明)。

#include<cstdio>
#include<algorithm>
#define N 500005
#define cmax(u,v) (u)<(v)?(u)=(v):0
using namespace std;
namespace ziqian
{
    typedef long long ll;
    const int INF = 1<<29;
    int in()
    {
        int r = 0, p = 0; char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) if(c == '-') p = 1;
        for(; c >='0' && c <='9'; c = getchar()) r = r * 10 + c - '0';
        return p?-r:r;  
    }
    struct line
    {
        int k; ll b;
        ll f(int x) {return (ll)k * x + b;}
        double operator * (line l){return (double)(b-l.b)/(l.k-k);}
    }con[N];
    struct modify
    {
        line L; int l, r;
    } mod[N*2], tmp_mod[N*2];
    ll ans[N];
    int n, m, last[N], tot, qcnt, q[N];
    char s[10];
    double px[N];
    bool cmp(modify a, modify b)
    {
        return a.L.k < b.L.k;
    }
    void solve(int ml, int mr, int ql, int qr)
    {
        if(ml > mr) return;
        int top = 0;
        for(int i = ml; i <= mr; i++)
            if(mod[i].l <= ql && qr <= mod[i].r)
            {
                line L = mod[i].L;
                while(top > 1)
                {
                    if(con[top].k == L.k)
                    {
                        if(con[top].b <= L.b) --top;
                        else break;
                    }
                    else if(L * con[top] <= con[top-1] * con[top])--top;
                    else break;
                }
                if(!(con[top].k == L.k && con[top].b >= L.b))con[++top] = L;
            }
        for(int i = 1; i < top; i++) px[i] = con[i] * con[i+1];
        px[top] = INF;
        for(int i = ql, cur = 1; cur <= top && i <= qr; i++)
        {
            for(; px[cur] < q[i] && cur <= top; ++cur);
            if(cur > top)break;
            ll tmp = con[cur].f(q[i]);
            cmax(ans[i], tmp);
        }
        if(ql == qr)return;

        int mid = (ql+qr)>>1, nl = ml-1, nr = mr+1;
        for(int i = ml; i <= mr; i++)
        {
            if(mod[i].l <= mid && (mod[i].l > ql || qr > mod[i].r)) ++nl, tmp_mod[nl] = mod[i];
            else --nr, tmp_mod[nr] = mod[i];
        }
        for(int i = nr, ii = (nr+mr)/2; i <= ii; i++) swap(tmp_mod[i], tmp_mod[nr+mr-i]);
        for(int i = ml; i <= mr; i++) mod[i] = tmp_mod[i];
        solve(ml, nl, ql, mid);

        int ll = nl+1, tmpcnt = ml-1;
        for(int i = ml; i <= nl || ll <= mr; )
        {
            if(ll > mr ||( i <= nl && mod[i].L.k < mod[ll].L.k)) tmp_mod[++tmpcnt] = mod[i], i++;
            else tmp_mod[++tmpcnt] = mod[ll], ll++;
        }
        for(int i = ml; i <= mr; i++) mod[i] = tmp_mod[i];

        nl = ml - 1; nr = mr + 1;
        for(int i = ml; i <= mr; i++)
        {
            if(mod[i].r > mid && (mod[i].l > ql || qr > mod[i].r)) ++nl, tmp_mod[nl] = mod[i];
            else --nr, tmp_mod[nr] = mod[i];
        }
        for(int i = nr, ii = (nr+mr)/2; i <= ii; i++) swap(tmp_mod[i], tmp_mod[nr+mr-i]);
        for(int i = ml; i <= mr; i++) mod[i] = tmp_mod[i];
        solve(ml, nl, mid+1,qr);

        ll = nl+1, tmpcnt = ml-1;
        for(int i = ml; i <= nl || ll <= mr; )
        {
            if(ll > mr ||( i <= nl && mod[i].L.k < mod[ll].L.k)) tmp_mod[++tmpcnt] = mod[i], i++;
            else tmp_mod[++tmpcnt] = mod[ll], ll++;
        }
        for(int i = ml; i <= mr; i++) mod[i] = tmp_mod[i];
    }
    void main()
    {
        n = in(), m = in();
        for(int i = 1; i <= n; i++) 
        {
            mod[++tot] = (modify){(line){0, in()}, 1, -1};
            last[i] = tot;
        }
        for(int i = 1, t; i <= m; i++)
        {
            t = in(); scanf("%s",s);
            if(s[0] == 'c') 
            {
                int pos = in(), kk = in();
                mod[last[pos]].r = qcnt; 
                mod[++tot] = (modify){(line){kk, mod[last[pos]].L.f(t) - (ll)kk * t}, qcnt+1, -1};
                last[pos] = tot;
            }
            else
                q[++qcnt] = t;
        }
        for(int i = 1; i <= tot; i++) if(mod[i].r == -1) mod[i].r = qcnt;
        for(int i = 1; i <= tot; i++) 
            if(mod[i].l > mod[i].r)
                mod[i] = mod[tot--];

        sort(mod+1,mod+1+tot,cmp);  
        solve(1, tot, 1, qcnt); 

        for(int i = 1; i <= tot; i++)
            mod[i].L.k *= -1, mod[i].L.b *= -1;
        sort(mod+1,mod+1+tot,cmp);  
        solve(1, tot, 1, qcnt);

        for(int i = 1; i <= qcnt; i++)
            printf("%lld\n",ans[i]);
    }
}
int main()
{
    ziqian::main();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值