• [BZOJ4311]向量[线段树分治+计算几何+二分/三分]


    一张手写的题解

    这些点一定在凸壳上

    证明可以参照gxz大佬的题解

    这个题的做法是按照询问作为时间轴,把每个插入的向量视为在一个时间区间 ([l,r]) 内有效,在 ([l,r]) 在线段树上对应的 (O(log n)) 个区间上打上标记,然后dfs一下整棵线段树,对于每个dfs到的线段树节点,遍历这个节点有的标记,维护出凸壳,然后在凸壳上二分斜率(也可以三分~),更新这个节点对应区间的询问的答案(这样不需要进行删除操作)

    对着std调了好久...

    每次二分是 (O(logn)) 每个节点被插入了 (O(logn)) 次,总共插入了 (O(nlogn))次,所以复杂度是 (O(nlog^2n))

    好像有个什么性质可以少个log,但这份代码居然跑进了前两页,所以似乎没必要了,其实是不想再写了

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e5 + 7;
    typedef long long ll;
    typedef long double lf;
    const lf eps = 1e-8;
    template<class A, class B> inline void chmax(A &a, B b) {
      if (a < b) a = b;
    }
    inline int read() {
      register int c = getchar(), x = 0;
      while (!isdigit(c)) c = getchar();
      while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
      return x;
    }
    struct Vec {
      int x, y;
      Vec(int x, int y) : x(x), y(y) {}
      Vec() {}
      inline Vec operator +(const Vec&b) const {return Vec(x + b.x, y + b.y);}
      inline Vec operator -(const Vec&b) const {return Vec(x - b.x, y - b.y);}
      inline ll operator *(const Vec&a) const {return x * 1ll * a.x + y * 1ll * a.y;}
      inline ll operator %(const Vec&a) const {return x * 1ll * a.y - y * 1ll * a.x;}
    } q[MAXN];
    struct atom {
      Vec a, b;//b是有效时间
    } a[MAXN];
    int n, op, x, y, sta[MAXN], top, tot, tot1; //因为栈存的是编号,所以数组嵌套有点多,可以存vec减少嵌套
    ll ans[MAXN];
    vector<int> t[530000];
    inline bool cmp(int x, int y) {
      if (a[x].a.x != a[y].a.x) return a[x].a.x < a[y].a.x;//按照x,y排序 求出凸壳
      return a[x].a.y < a[y].a.y;
    }
    inline void add(int o, int l, int r, int ql, int qr, int v) {
      if (ql > qr) return ;
      if (ql <= l && r <= qr) return void(t[o].push_back(v));
      int mid = l + r >> 1;
      if (ql <= mid) add(o << 1, l, mid, ql, qr, v);
      if (qr > mid) add(o << 1 | 1, mid + 1, r, ql, qr, v);
    }
    inline lf slope(const Vec &a, const Vec &b) {
      if (fabs(a.x - b.x) < eps) return 1e9;
      return lf(a.y - b.y) / (a.x - b.x);
    }
    inline ll query(int o, int pos) { //二分q[pos]垂线的斜率处于凸包的哪个位置
      lf K = -1.0 * q[pos].x / q[pos].y;
      //-1.0 / (q[pos].y / q[pos].x);
      if (top == 1 || K > slope(a[t[o][sta[1]]].a, a[t[o][sta[2]]].a) + eps) return q[pos] * a[t[o][sta[1]]].a;
      if (K + eps < slope(a[t[o][sta[top - 1]]].a, a[t[o][sta[top]]].a)) return q[pos] * a[t[o][sta[top]]].a;//判边界,不知道哪些不需要...但判了总没坏处
      int l = 2, r = top, ans = 1;
      while (l <= r) {
        int mid = l + r >> 1;
        if (K < slope(a[t[o][sta[mid - 1]]].a, a[t[o][sta[mid]]].a) + eps) ans = mid, l = mid + 1;
        else r = mid - 1;
      }
      return q[pos] * a[t[o][sta[ans]]].a;
    }
     
    inline void solve(int o, int l, int r) {
      if (!t[o].size()) return ;
      sort(t[o].begin(), t[o].end(), cmp);
      top = 0;
      for (int i = 0; i < t[o].size(); ++i) {
        while (top > 1 && (a[t[o][i]].a - a[t[o][sta[top - 1]]].a) % (a[t[o][sta[top]]].a - a[t[o][sta[top - 1]]].a) <= 0) --top;//维护凸壳
        sta[++top] = i;
      }
      for (int i = l; i <= r; ++i) chmax(ans[i], query(o, i));
    }
     
    inline void dfs(int o, int l, int r) {
      solve(o, l, r);
      if (l == r) return ;
      int mid = l + r >> 1;
      dfs(o << 1, l, mid), dfs(o << 1 | 1, mid + 1, r);
    }
     
    int main() {
      int m = read();
      while (m--) {
        op = read(), x = read();
        if (op != 2) {
          y = read();
          if (op == 1) a[++tot1] = (atom) {Vec(x, y), Vec(tot + 1, -1)};
          else q[++tot] = Vec(x, y);
        }
        else a[x].b.y = tot;
      }
      for (int i = 1; i <= tot1; ++i) add(1, 1, tot, a[i].b.x, a[i].b.y == -1 ? tot : a[i].b.y, i);
      dfs(1, 1, tot);
      for (int i = 1; i <= tot; ++i) printf("%lld
    ", ans[i]);
      return 0;
    }
    
  • 相关阅读:
    最近几个月的感想
    Fortran 入门——C#调用Fortran DLL
    Fortran 入门——函数调用
    JQueryAjax初体验和一点感想
    【HDU】1796 How many integers can you find
    【SGU】476 Coach's Trouble
    【HDU】2204 Eddy's爱好
    【POJ】1091 跳蚤
    【URAL】1091 Tmutarakan Exams
    【ZOJ】2836 Number Puzzle
  • 原文地址:https://www.cnblogs.com/storz/p/10192431.html
Copyright © 2020-2023  润新知