CF1583G Omkar and Time Travel

发布时间 2023-11-07 08:50:04作者: DCH233

CF1583G Omkar and Time Travel

想清楚了就不难。

首先我们考察一下性质,一次 time leap 之后只有包含于 \((a_i, b_i)\) 的区间会被重置,考虑这样一件事情:设 \(f_{l,r}\) 表示从 \(l\) 左边走到 \(r\) 右边的 time leap 次数。那么转移是简单的。

这个 dp 感觉是很有用的,看一下有什么用。考察如何到达最终状态,不难发现是每次走到当前的最大值,然后变成子问题缩小规模,那么可以维护出当前 \((l,r)\) 这个区间内的任务还没有完成,答案就是若干个 \(f_{l,r}\) 相加的形式。具体是哪些可以对 \(s\) 排序后求出。

这时候状态数是 \(O(n^2)\) 的,考虑优化,不妨重新设 \(f_i\) 表示从第 \(i\) 个区间右端点做了一次 time leap 后把中间的任务重新完成所需的次数,那么就有:

\[f_i = \sum_{I(j) \subseteq I(i)} f_j + 1 \]

其中 \(I(x)\) 表示 \(x\) 对于的区间。那么这个就可以扫描线 + 树状数组维护了。我们原来的那个 dp 可以看做区间内的 \(f\) 相加,这样就转化为了二维偏序问题,可以直接做到 \(O(n \log n)\)

const int P = 1e9 + 7;
void add(int &x, int y) {
  (x += y) >= P ? x -= P : 0;
}

const int N = 2e5 + 10;

int n;
struct Travel {
  int a, b, id;
}a[N];
int f[N], r[N];
int t, s[N];
int q[N << 1];

struct BIT {
  int tr[N << 1];
  int lowbit(int x) {
    return x & -x;
  }
  void add(int x, int y) {
    for(; x; x -= lowbit(x))
      ::add(tr[x], y);
  }
  int query(int x) {
    int res = 0;
    for(; x <= 2 * n; x += lowbit(x))
      ::add(res, tr[x]);
    return res;
  }
  void clear() {
    for(int i = 1; i <= 2 * n; ++i)
      tr[i] = 0;
  }
}seg;

int main() {
  read(n);
  for(int i = 1; i <= n; ++i)
    read(a[i].a, a[i].b), a[i].id = i;
  sort(a + 1, a + n + 1, [](Travel x, Travel y) {
    return x.b < y.b;
  });
  for(int i = 1; i <= n; ++i)
    r[a[i].id] = i;
  for(int i = 1; i <= n; ++i) {
    f[i] = seg.query(a[i].a) + 1;
    seg.add(a[i].a, f[i]);
  }
  read(t);
  priority_queue<pair<int, int>> que;
  for(int i = 1; i <= t; ++i) {
    read(s[i]), s[i] = r[s[i]];
    que.push(make_pair(a[s[i]].b, a[s[i]].a));
  }
  int cur = 1;
  while(que.size()) {
    while(que.size() && que.top().second < cur)
      que.pop();
    if(!que.size()) break;
    auto u = que.top(); que.pop();
    q[u.first - 1] = cur, cur = u.second;
  }
  int ans = 0;
  seg.clear();
  for(int i = 1, j = 1; i <= 2 * n; ++i) {
    if(a[j].b == i) seg.add(a[j].a, f[j]), j++;
    if(q[i]) add(ans, seg.query(q[i]) + 1);
  }
  printf("%d\n",ans);
}