zoukankan      html  css  js  c++  java
  • BZOJ 4311: 向量( 按时间分治 + 线段树 )

    离线, 然后按时间分治, 每个向量都有出现时间[l, r], 直接插入时间线段树(一个向量只会影响O(logN)数量级的线段树节点). 在线段树每个节点弄出凸壳然后二分. 时间复杂度O(Nlog^2N)

    ---------------------------------------------------------------------------

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    typedef long long ll;
    #define V(x) v[p[x]]
    #define C(x) v[c[x]]
    #define Q(x) q[_q[x]]
    #define K(a, b) ((double) (a.y - b.y) / (a.x - b.x))
     
    const int maxn = 200009;
     
    int N, T, qn, vn, pn, cn;
    int p[maxn], _q[maxn], c[maxn];
    double lk[maxn], rk[maxn];
    ll ans[maxn];
    int buf[20];
     
    inline int getint() {
    char c = getchar();
    for(; !isdigit(c); c = getchar());
    int ret = 0;
    for(; isdigit(c); c = getchar())
    ret = ret * 10 + c - '0';
    return ret;
    }
     
    inline void putint(ll x) {
    if(!x) {
    puts("0");
    } else {
    int n = 0;
    for(; x; x /= 10) buf[n++] = x % 10;
    while(n--) putchar(buf[n] + '0');
    puts("");
    }
    }
     
    struct Q {
    int p, x, y;
    } q[maxn];
     
    struct V {
    int x, y, l, r;
    } v[maxn];
     
    struct L {
    int p;
    L* nxt;
    } Lpool[maxn * 50], *Lpt = Lpool;
     
    inline void AddL(L*&t) {
    Lpt->p = T;
    Lpt->nxt = t;
    t = Lpt++;
    }
     
    struct Node {
    Node *lc, *rc;
    L* v;
    } pool[maxn << 1], *pt = pool, *Root;
     
    void Modify(Node* t, int l, int r) {
    if(v[T].l <= l && r <= v[T].r) {
    AddL(t->v);
    } else {
    int m = (l + r) >> 1;
    if(v[T].l <= m) Modify(t->lc, l, m);
    if(m < v[T].r) Modify(t->rc, m + 1, r);
    }
    }
     
    void Build(Node* t, int l, int r) {
    if(l != r) {
    int m = (l + r) >> 1;
    Build(t->lc = pt++, l, m);
    Build(t->rc = pt++, m + 1, r);
    }
    }
     
    bool Cmp(const int &l, const int &r) {
    return v[l].x < v[r].x || (v[l].x == v[r].x && v[l].y < v[r].y);
    }
     
    void Solve(Node* t, int l, int r) {
    if(l != r) {
    int m = (l + r) >> 1;
    Solve(t->lc, l, m);
    Solve(t->rc, m + 1, r);
    }
    pn = cn = 0;
    for(L* o = t->v; o; o = o->nxt) p[pn++] = o->p;
    if(!pn) return;
    sort(p, p + pn, Cmp);
    c[cn++] = p[0];
    for(int i = 1; i < pn; i++) {
    while(cn && V(i).x == C(cn - 1).x) cn--;
    while(cn > 1 && K(V(i), C(cn - 1)) > K(C(cn - 1), C(cn - 2))) cn--;
    c[cn++] = p[i];
    }
    lk[0] = 1e30, rk[cn - 1] = -1e30;
    for(int i = 1; i < cn; i++)
    lk[i] = rk[i - 1] = K(C(i), C(i - 1));
    for(int i = l; i <= r; i++) if(~_q[i]) {
    int _l = 0, _r = cn - 1;
    double k = -1.0 * Q(i).x / Q(i).y;
    while(_l <= _r) {
    int m = (_l + _r) >> 1;
    ans[_q[i]] = max(ans[_q[i]], ll(C(m).x) * Q(i).x + ll(C(m).y) * Q(i).y);
    (k < lk[m] && k < rk[m]) ? _l = m + 1 : _r = m - 1;
    }
    }
    }
     
    void Work() {
    Build(Root = pt++, 1, N);
    for(T = 0; T < vn; T++) Modify(Root, 1, N);
    pn = 0;
    Solve(Root, 1, N);
    for(int i = 0; i < qn; i++) putint(ans[i]);
    }
     
    void Init() {
    N = getint();
    qn = vn = 0;
    memset(_q, -1, sizeof _q);
    for(int i = 1; i <= N; i++) {
    int t = getint();
    if(t == 3) {
    _q[i] = qn;
    q[qn].x = getint(), q[qn].y = getint();
    q[qn++].p = i;
    } else if(t == 1) {
    v[vn].x = getint(), v[vn].y = getint();
    v[vn].l = i, v[vn++].r = N;
    } else
    v[getint() - 1].r = i;
    }
    memset(ans, 0, sizeof ans);
    }
     
    int main() {
    Init();
    Work();
    return 0;
    }

    --------------------------------------------------------------------------- 

    4311: 向量

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 58  Solved: 26
    [Submit][Status][Discuss]

    Description

    你要维护一个向量集合,支持以下操作:
    1.插入一个向量(x,y)
    2.删除插入的第i个向量
    3.查询当前集合与(x,y)点积的最大值是多少。如果当前是空集输出0

    Input

    第一行输入一个整数n,表示操作个数
    接下来n行,每行先是一个整数t表示类型,如果t=1,输入向量
    (x,y);如果t=2,输入id表示删除第id个向量;否则输入(x,y),查询
    与向量(x,y)点积最大值是多少。
    保证一个向量只会被删除一次,不会删没有插入过的向量

    Output

    对于每条t=3的询问,输出一个答案

    Sample Input

    5
    1 3 3
    1 1 4
    3 3 3
    2 1
    3 3 3

    Sample Output

    18
    15

    HINT

    n<=200000 1<=x,y<=10^6

    Source

  • 相关阅读:
    一些 SQLite技巧
    linux增加swap空间
    linux解压命令
    数据库常用语句
    服务器命令
    Clickhouse高可用配置总结
    MySQL笔记
    Linux查看硬件信息
    Greenplum安装
    ClickHouse学习笔记
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5137681.html
Copyright © 2011-2022 走看看