ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LOJ #3006. 「JOISC 2015 Day 4」防壁

2022-03-26 10:34:26  阅读:197  来源: 互联网

标签:LOJ 线段 pmx len JOISC int 3006 Maxn qi


LOJ #3006. 「JOISC 2015 Day 4」防壁

​ 首先有一个很显然的结论是:对于每条线段,贪心地向询问点移动直到覆盖的方案一定是最优的。于是我们就得到了一个 \(\mathcal O(NM)\) 的暴力做法。

​ 我们先考虑Subtask2也就是 \(a_i=0\) 的情况怎么做。对于线段 \([0,t]\) 我们定义询问点 \(x_i\) 是重要的当且仅当该线段在为了覆盖 \(x_i\) 时做出了贡献,否则则称 \(x_i\) 是非重要的。关于这个定义容易有以下结论:

  1. 对于一个询问点 \(x_i\) 如果其对于线段 \([0,t]\) 是重要的,那么 \(x_i\) 对于线段 \([0,t-1]\) 也是重要的。
  2. 如果询问点 \(x_i\) 对线段 \([0,t]\) 是重要的,并且满足关系 \(x_{i-1}<x_i\),那么该线段在覆盖了 \(x_i\) 之后的位置是 \([x_i-t,x_i]\);反之若满足关系 \(x_{i-1}>x_i\),那么位置就是 \([x_i,x_i+t]\)。

对于询问点 \(x_i\) 我们定义 \(f(x_i)\) 是满足”\(x_i\) 对线段 \([0,t]\) 是重要的“的最大的 \(t\)。先考虑如何求出 \(f(x_i)\)。注意到 \(f(x_i)\) 的极值性,我们考虑整体二分。对于线段 \([0,t]\) 我们要判断 \(x_i\) 是否重要,那就必须要求出该线段在询问点 \(x_i\) 之前的位置,也就是上一个对线段 \([0,t]\) 重要的询问点 \(x_i'\);考虑到整体二分过程中右边有对左边的贡献,用一个数组维护这个值即可。

​ 然后我们思考在求出 \(f(x_i)\) 之后如何求出答案。假设当前的线段为 \([0,t]\),容易发现若询问点 \(x_i\) 对该线段是非重要的,那么它对这个线段没有任何影响。于是只需要考虑所有对 \([0,t]\) 重要的询问点 \(x_i\) 组成的询问点序列 \(y_1\ldots y_m\)。容易发现 \(y_1\ldots y_m\) 对 \([0,t]\) 都有贡献,不妨先假设线段 \([0,t]\) 移动相邻的询问点 \(y_i\rightarrow y_{i+1}\) 都需要移动 \(|y_{i+1}-y_i|\) 格,而若 \([y_{i-1}<y_i]\neq [y_i<y_{i+1}]\) 即询问点序列在 \(i\) 处形成了一个拐点,那么线段 \([0,t]\) 就可以少移动 \(t\) 格。如果设序列 \(y\) 中拐点的数量为 \(c\),那么线段 \([0,t]\) 的答案为 \(\sum\limits_{i=1}^m|y_i-y_{i-1}|-c\cdot t\)。我们把所有的线段 \([0,t_i]\) 按长度排序,然后动态维护询问点序列 \(y_1\ldots y_m\) 和其中拐点的数量。这样Subtask2就做完了,时间复杂度是整体二分的复杂度 \(\mathcal O(M\log N)\)。

​ 然后我们考虑一般情况 \([a_i,b_i]\)。设 \(t_i=b_i-a_i\) 我们考虑算出 \([a_i,b_i]\) 的答案减去 \([0,t_i]\) 的答案 ( 记其为 \(w\) ) 于是观察线段 \([a_i,b_i]\) 和 \([0,t_i]\) 的移动。找到最小的 \(p\) 满足存在 \(q<p\) 使得 \(|x_p-x_q|>t_i\)。若不存在这样的 \(p\) 此时线段 \([a_i,b_i]\) 和 \([0,t_i]\) 只会分别往一个方向移动,这是很容易的。对于新定义的 \(p\) 我们可以发现一些结论:

  1. 在覆盖完询问点 \(x_p\) 之后线段 \([a_i,b_i]\) 和 \([0,t_i]\) 位置一样;
  2. 在覆盖询问点 \(x_p\) 之前线段 \([a_i,b_i]\) 和 \([0,t_i]\) 只会分别往一个方向移动。

于是我们直接二分求出 \(p\) 之后就可以很容易算出 \(w\) 了。这样一般情况也做完了。

​ 时间复杂度为 \(\mathcal O(N\log M+M\log N)\),空间复杂度为 \(\mathcal O(n)\)。由于所有带 \(\log\) 的地方都是二分,因此该做法的常数较小。

参考代码
#include <bits/stdc++.h>
using namespace std;
static constexpr int inf = 0x3f3f3f3f;
static constexpr int Maxn = 2e5 + 5;
int n, m, a[Maxn], b[Maxn];
pair<int, int> c[Maxn], q[Maxn];
int64_t ans[Maxn];
int p[Maxn], dir[Maxn], pmn[Maxn], pmx[Maxn], pdif[Maxn];
int qi[Maxn], pt[Maxn], pre[Maxn];
void divide(int l, int r, int ql, int qr) {
  if (l > r || ql > qr) return ;
  if (l == r) {
    for (int i = ql; i <= qr; ++i) pt[qi[i]] = l;
  } else {
    int mid = (l + r + 1) / 2, qn1 = 0, qn2 = 0;
    static int q1[Maxn], q2[Maxn];
    const int len = c[mid].first;
    int xl = 0, xr = len, t = 0;
    for (int i = ql; i <= qr; ++i) {
      if (pre[qi[i]] > t) {
        t = pre[qi[i]];
        if ( dir[t]) xr = p[t], xl = xr - len;
        if (!dir[t]) xl = p[t], xr = xl + len;
      }
      if (xr < p[qi[i]] || xl > p[qi[i]]) {
        t = q2[++qn2] = qi[i];
        if (xr < p[t]) xr = p[t], xl = xr - len;
        if (xl > p[t]) xl = p[t], xr = xl + len;
      } else q1[++qn1] = qi[i], pre[qi[i]] = t;
    }
    for (int i = 1; i <= qn1; ++i) qi[ql + i - 1] = q1[i];
    for (int i = 1; i <= qn2; ++i) qi[ql + qn1 + i - 1] = q2[i];
    divide(l, mid - 1, ql, qr - qn2);
    divide(mid, r, qr - qn2 + 1, qr);
  }
} // divide
int main(void) {
  extern uint32_t readu32(void);
  n = readu32(), m = readu32();
  for (int i = 1; i <= n; ++i) {
    a[i] = readu32(), b[i] = readu32();
    c[i] = pair(b[i] - a[i], i);
  } sort(c + 1, c + n + 1);
  for (int i = 1; i <= m; ++i)
    p[i] = readu32(), dir[i] = (p[i] > p[i - 1]);
  iota(qi + 1, qi + m + 1, 1), divide(0, n, 1, m);
  for (int i = 1; i <= m; ++i) q[i] = pair(pt[i], i);
  sort(q + 1, q + m + 1);
  int64_t cur = 0, turn = 0;
  auto upd = [&](int x, int y, int w) {
    if (x > m || y > m) return;
    cur += w * abs(p[x] - p[y]);
    turn += w * (dir[x] != dir[y]);
  }; // main()::upd
  auto calc = [&](int x) { return cur - turn * x; };
  for (int i = 1; i <= m; ++i) upd(i - 1, i, 1);
  static int prv[Maxn], nxt[Maxn];
  for (int i = 1; i <= m; ++i) prv[i] = i - 1;
  for (int i = 1; i <= m; ++i) nxt[i] = i + 1;
  for (int i = 1, j = 1; i <= n; ++i) {
    while (j <= m && q[j].first < i) {
      int x = q[j].second;
      int l = prv[x], r = nxt[x];
      upd(l, x, -1), upd(r, x, -1);
      nxt[l] = r, prv[r] = l;
      upd(l, r, +1); ++j;
    } ans[c[i].second] = calc(c[i].first);
  }
  pmn[0] = inf, pmx[0] = 0;
  for (int i = 1; i <= m; ++i) {
    pmn[i] = min(pmn[i - 1], p[i]);
    pmx[i] = max(pmx[i - 1], p[i]);
    pdif[i] = pmx[i] - pmn[i];
  }
  for (int i = 1; i <= n; ++i) {
    const int len = b[i] - a[i];
    int j = upper_bound(pdif + 1, pdif + m + 1, len) - pdif;
    if (j == m + 1) {
      auto inter = [&](int l1, int r1, int l2, int r2)
        { return max<int>(0, max(r2 - r1, l1 - l2)); };
      int ori = inter(a[i], b[i], pmn[m], pmx[m]);
      int cur = inter(0, len, pmn[m], pmx[m]);
      ans[i] += ori - cur;
    } else {
      auto calc = [&](int l, int r) {
        int64_t res = 0;
        if (l > pmn[j - 1]) res += l - pmn[j - 1], l = pmn[j - 1], r = l + len;
        else if (r < pmx[j - 1]) res += pmx[j - 1] - r, r = pmx[j - 1], l = r - len;
        if (l > pmn[j]) res += l - pmn[j], l = pmn[j], r = l + len;
        else if (r < pmx[j]) res += pmx[j] - r, r = pmx[j], l = r - len;
        return res;
      };
      ans[i] += calc(a[i], b[i]) - calc(0, len);
    }
  }
  for (int i = 1; i <= n; ++i)
    printf("%lld\n", ans[i]);
  exit(EXIT_SUCCESS);
} // main
// fast io
static const int _BUF_SIZE = 1 << 18;
static char _ibuf[_BUF_SIZE], *iS = _ibuf, *iT = _ibuf;
inline char getch(void) {
  if (__builtin_expect(iS == iT, false))
    iT = (iS = _ibuf) + fread(_ibuf, 1, _BUF_SIZE, stdin);
  if (__builtin_expect(iS == iT, false)) return EOF;
  else return *iS++;
} // getch
uint32_t readu32(void) {
  register uint32_t x = 0;
  register char ch = getch();
  while (ch < '0' || ch > '9') ch = getch();
  while (ch >= '0' && ch <= '9') ((x += (x << 2)) <<= 1) += (ch ^ '0'), ch = getch();
  return x;
} // readu32

标签:LOJ,线段,pmx,len,JOISC,int,3006,Maxn,qi
来源: https://www.cnblogs.com/cutx64/p/16057864.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有